`
qzriso
  • 浏览: 242583 次
  • 性别: Icon_minigender_1
  • 来自: ph
社区版块
存档分类
最新评论

在VC++中实现无标题栏对话框的拖动

阅读更多

目前,很多基于对话框的应用程序中对话框都是不带框架的,也就是说对话框没有标题栏。众所周知,窗口的移动都是通过鼠标拖动窗口的标题栏来实现的,那么现在应用程序中的对话框没有了标题栏,用户如何移动对话框呢?本实例针对这个问题提出解决的办法。程序编译运行后的界面效果如图一所示:


图一、无标题栏的对话框界面


  一、实现方法

  解决无标题栏窗口的拖动问题有两种方案,一种方案是使用常规思路来处理鼠标拖拽事件,当窗口获得WM_LBUTTONDOWN(OnLButtonDown)时,通过设置标志并调用CWnd::SetCapture()函数来让当前窗口捕捉鼠标消息,应用程序进入移动模式,此时只要有WM_MOUSEMOVE消息过来,就可以据此移动框架窗口,最后当用户释放鼠标按钮,则WM_LBUTTONUP消息处理例程清除标志并调用CWnd::ReleaseCapture()函数将鼠标控制返还给Windows。这种方法比较繁琐,首先要决定窗口准备移到哪?然后要想好如何重绘窗口等等,而且根据屏幕显示属性对话框"效果"页中"视觉效果"项的"拖动时显示窗口中内容"复选框是不是选中,拖动效果是不同的。那么你怎么知道设置的信息呢?方法是调用SystemParametersInfo(SPI_GETDRAGFULLWINDOWS)。Windows要程序员来事无巨细地处理这些繁琐的事情真是太糟了。

  由于Windows本身知道通过鼠标点住标题栏可以移动窗口,那么能不能将鼠标在窗口客户区任何地方的点击拖动行为都模仿成好像是在标题栏中一样呢?答案是肯定的,这样就产生了第二种拖动窗口移动的方法。实际上,用鼠标点住对话框背景进行拖动操作并不难,但是你必须了解在标题栏里拖动窗口的原理。Windows首先确定鼠标点中了哪个窗口,然后向那个窗口发送一个WM_NCHITTEST消息找出此窗口的哪个"非客户区"(如边界、最大化/最小化按钮、菜单、标题等等)拥有鼠标光标。接着默认的窗口过程响应消息并返回一个特定的代码。如果鼠标指针落在标题栏中,那么这个特定代码就是HTCAPTION,此时Windows便进入拖拽模式,以便用户能够对窗口进行移动操作。所以要想在客户区里用鼠标拖动对话框,那么只要在客户区里模仿标题栏里的鼠标拖动行为即可。下面的代码通过处理WM_NCHITTEST消息实现了对话框的拖动操作:

UINT CMyDialog::OnNcHitTest(CPoint pt)
{
 CRect rc;
 GetClientRect(&rc);
 ClientToScreen(&rc);
 return rc.PtInRect(pt) ? HTCAPTION : CDialog::OnNcHitTest(pt);
}


  上面这个代码很容易理解,当鼠标落在客户区内,函数返回HTCAPTION。对于一个简单的对话框来说,仅仅用这个代码就完全可以实现在对话框背景内的拖动操作。因为Windows使用z-order坐标来确定鼠标下是哪个窗口,所以对话框中其它的所有对象照常工作。如果用户单击某个控制,只要这个控制不是静态位图图像或者文本,那么Windows都将鼠标事件发送到该控制上,而不是对话框。由于静态位图图像或者文本对于对话框是透明的,所以鼠标在上面的拖动同样实现移动,而对于对话框中的编辑框、按钮、组合框等其它非静态控制则按通常的行为方式运行。

  如果应用不是一个纯粹的对话框程序,而是是包含CFormView或其它非对话框视图,处理方法几乎是一样的,只需在视图代码中做一点小小的改动即可,因为Windows在发送WM_NCHITTEST消息时,是将它发送到鼠标光标下的框架/视图最顶层非透明窗口,由于视图首先获得WM_NCHITTEST消息。所以只要在视图的WM_NCHITTEST消息处理例程中返回HTTRANSPARENT,让视图对鼠标点击"透明"即可。注意是在视图中,而不是在框架中加入下面代码:

UINT CMyView::OnNcHitTest(CPoint pt)
{
 return HTTRANSPARENT;
}


  这样做以后,Windows将忽略视图并继续搜索能接收WM_NCHITTEST的窗口。如果顺利的话,将找到父窗口,这时用与对话框相同的WM_NCHITTEST处理代码即可,即在客户区中的点击返回HTCAPTION。你甚至可以通过鼠标坐标的象素计算,在规定的局部范围内实现视图透明。

  二、编程步骤

  1、 启动Visual C++6.0,生成一个基于对话框的应用程序,将该程序命名为"DragMovDlg";

  2、 将程序中对话框的Style设置为"PopUp",Border设置为"None";

  3、 使用Class Wizard为对话框添加WM_NCHITTEST消息响应处理函数;

  4、 添加代码,编译运行程序。

三、程序代码

/////////////////////////////////////////////// DragMoveDlgDlg.h : header file
#if !defined(AFX_DRAGMOVEDLGDLG_H__4E4722C8_DE78_4AEC_97BC_73CEB2B525B3__INCLUDED_)
#define AFX_DRAGMOVEDLGDLG_H__4E4722C8_DE78_4AEC_97BC_73CEB2B525B3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMyDialog : public CDialog
{
 // Construction
 public:
  CMyDialog(CWnd* pParent = NULL); // standard constructor
  // Dialog Data
  //{{AFX_DATA(CMyDialog)
   enum { IDD = IDD_DRAGMOVEDLG_DIALOG };
   // NOTE: the ClassWizard will add data members here
  //}}AFX_DATA
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CMyDialog)
 protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  //}}AFX_VIRTUAL
  // Implementation
 protected:
  HICON m_hIcon;
  // Generated message map functions
  //{{AFX_MSG(CMyDialog)
   virtual BOOL OnInitDialog();
   afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
   afx_msg void OnPaint();
   afx_msg HCURSOR OnQueryDragIcon();
  //}}AFX_MSG
  afx_msg UINT OnNcHitTest(CPoint pt);
  DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_DRAGMOVEDLGDLG_H__4E4722C8_DE78_4AEC_97BC_73CEB2B525B3__INCLUDED_)

//////////////////////////////////////////////////////////////////////// DragMoveDlgDlg.cpp : implementation file
#include "stdafx.h"
#include "DragMoveDlg.h"
#include "DragMoveDlgDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)
: CDialog(CMyDialog::IDD, pParent)
{
 //{{AFX_DATA_INIT(CMyDialog)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CMyDialog)
  // NOTE: the ClassWizard will add DDX and DDV calls here
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
 //{{AFX_MSG_MAP(CMyDialog)
   ON_WM_SYSCOMMAND()
   ON_BN_CLICKED(ID_APP_ABOUT,OnAbout)
   ON_WM_PAINT()
   ON_WM_QUERYDRAGICON()
 //}}AFX_MSG_MAP
 ON_WM_NCHITTEST()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyDialog message handlers
BOOL CMyDialog::OnInitDialog()
{
 CDialog::OnInitDialog();
 // Add "About..." menu item to system menu.
 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);
 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
   pSysMenu->AppendMenu(MF_SEPARATOR);
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  }
 }
 // Set the icon for this dialog. The Framework does this automatically
 // when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE); // Set big icon
 SetIcon(m_hIcon, FALSE); // Set small icon
 // TODO: Add extra initialization here
 return TRUE; // return TRUE unless you set the focus to a control
}

void CMyDialog::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {}
 else
 {
  CDialog::OnSysCommand(nID, lParam);
 }
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMyDialog::OnPaint()
{
 if (IsIconic())
 {
  CPaintDC dc(this); // device context for painting
  SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  // Center icon in client rectangle
  int cxIcon = GetSystemMetrics(SM_CXICON);
  int cyIcon = GetSystemMetrics(SM_CYICON);
  CRect rect;
  GetClientRect(&rect);
  int x = (rect.Width() - cxIcon + 1) / 2;
  int y = (rect.Height() - cyIcon + 1) / 2;
  // Draw the icon
  dc.DrawIcon(x, y, m_hIcon);
 }
 else
 {
  CDialog::OnPaint();
 }
}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMyDialog::OnQueryDragIcon()
{
 return (HCURSOR) m_hIcon;
}

void CMyDialog::OnAbout()
{
 CAboutDlg().DoModal();
}

//////////////////
// Non-client hit-test handler to move window by its client area.
// If the user clicks anywhere on the client area, pretend it's the
// caption. Windows does the rest!
UINT CMyDialog::OnNcHitTest(CPoint pt)
{
 CRect rc;
 GetClientRect(&rc);
 ClientToScreen(&rc);
 return rc.PtInRect(pt) ? HTCAPTION : CDialog::OnNcHitTest(pt);
}


  四、小结

  本实例主要探讨了如何处理WM_HITTEST消息来"欺骗"Windows当前鼠标就在程序的标题栏中,从而实现对话框窗体的拖动。这种方法不仅适用于对话框程序,对于视图文档结构的应用程序也是适用的。

分享到:
评论

相关推荐

    vc 无标题栏对话框拖拽

    为了实现无标题栏对话框的拖拽,我们需要重载`CDialog`或其派生类的`OnNcHitTest`函数,并在其中判断鼠标位置。当鼠标在我们想要定义为拖拽区域的位置时,返回`HTCAPTION`。例如: ```cpp void CMyDialog::...

    VC++实现无标题栏对话框的拖动

    内容索引:VC/C++源码,界面编程,拖动 VC++实现无标题栏对话框的拖动,很多基于对话框的应用程序都是不带框架的,也就是说对话框没有标题栏。众所周知,窗口的移动都是通过鼠标点住标题栏拖动窗口实现的,那么现在...

    VC 无标题栏窗口的拖动实现.rar

    这个例子展示了如何在VC++中实现无标题栏窗口的拖动,使得用户可以通过鼠标在窗口顶部或者其他自定义区域按住并移动来改变窗口的位置。这种方法适用于那些需要自定义界面的程序,可以提供更灵活的设计空间。同时,这...

    VC 可在对话框的任意位置拖动对话框

    在VC++编程环境中,开发对话框(Dialog)应用...通过查看和运行这个示例,你可以更直观地了解这一功能的具体实现,进一步加深对VC++对话框拖动的理解。学习并理解这个实例,将有助于你在实际项目中灵活运用这一功能。

    VC++可窗口拖动的无边框、无标题栏窗体

    摘要:VC/C++源码,数据库应用,窗口拖动,无边框窗体 VC++源码实现一个可拖动窗口的无边框、无标题栏窗口实例,示例演示截图看似一张图片,实则上是VC编程实现的无边框无标题栏的窗口,而且加入了拖动功能,鼠标按住...

    vc.rar_vc carry_对话框_对话框边框_标题栏 VC_标题栏按钮

    在VC++编程环境中,开发一个具有自定义标题栏和边框的对话框程序是一项常见的任务。这涉及到对Windows API的深入理解和使用,特别是在处理窗口消息和控件绘图方面。以下是一些关于这个主题的关键知识点: 1. **...

    visual c++自绘窗口漂亮的标题栏

    10. **测试与调试**:在实现自绘标题栏后,必须进行充分的测试,确保在不同的屏幕分辨率、 DPI 设置以及系统主题下都能正确显示和操作。 总之,"visual c++自绘窗口漂亮的标题栏"是一项涉及多种技术和技巧的任务,...

    vcMoveDlg2_VC++源码_

    5. **On_WM_NCHITTEST()** 和 **On_WM_NCMOUSEMOVE()**:这两个消息处理函数在非客户区(如标题栏或边框)的鼠标操作时被触发,对于实现窗口拖动功能至关重要。 在实际的源码中,你可能会看到以下关键部分: - `...

    标题栏重绘 VC MFC

    在VC++ MFC环境中,标题栏的重绘是一项常见的自定义UI操作,它允许开发者根据自己的需求设计出独特的用户界面,提升应用的视觉效果。本文将深入探讨如何在MFC中实现标题栏的自定义重绘,以及在这个过程中可能遇到的...

    自制标题栏

    在实现过程中,我们可能还需要用到GDI(Graphics Device Interface)或GDI+来绘制标题栏的图形元素,如背景色、文字和按钮图标。同时,为了实现拖动窗口的功能,需要处理`WM_NCLBUTTONDOWN`和`WM_NCMOUSEMOVE`消息。...

    vc 窗口标题栏替换例程

    在本例中,你可能需要创建自定义的位图资源,作为标题栏的新背景,以及对话框的边框样式。 5. **消息处理**: 自定义标题栏和边框后,你还需要处理鼠标和键盘消息,以便实现拖动、最大化和最小化等操作。这需要...

    VC++经验技巧宝典配套代码06章

    0334拖动没有标题栏的窗体 0335获取标题栏的内容 0336滚动的窗体标题栏 0337无标题对话框的拖动方法 6.2窗体的位置和大小控制 0339不可移动的窗体 0340始终在最上面的窗体 0341跟随鼠标移动的窗体 0342控制窗体的...

    MFC-vc++-vs2010对话框窗口靠边自动隐藏(仿QQ抽屉式)

    在本文中,我们将深入探讨如何在Visual Studio 2010环境下使用Microsoft Foundation Class (MFC)库来创建一个仿QQ的抽屉式对话框窗口,实现窗口靠边自动隐藏的功能。这一技术常用于增强软件界面的用户体验,使得用户...

    duihuakuang.rar_VC 对话框 多

    "实例141——可在对话框的任意位置拖动对话框"则展示了如何使对话框具有可移动性,用户可以通过鼠标拖动对话框的标题栏或指定区域来改变其位置。 "实例133——设置对话框的背景颜色"讲解了如何自定义对话框的背景色...

    VC对话框隐藏运行--悬浮窗口

    【VC对话框隐藏运行--悬浮窗口】是一种在VC++编程中实现特定用户界面效果的技术,主要是创建一个没有边框、可以自由移动并且在任务栏中不显示的小窗口,通常用于提供快捷操作或辅助功能。本篇文章将详细讲解如何在...

    VC++常用函数

    在VC++中获取本地IP地址可以通过调用Windows API函数实现。常见的方法是使用`WSAStartup`初始化网络库,然后使用`gethostbyname`或`gethostbyaddr`函数来获取主机信息,并从中解析出IP地址。 --- #### VC调用CHM...

    vc++从零开始讲义

    - 在对话框属性中,取消勾选“具有边框的窗口”选项,同时勾选“顶级”选项,使对话框没有标题栏且始终位于其他窗口之上。 2. **修改TextControl的属性**: - 选择TextControl控件,打开其属性页签,将文本对齐...

    vc++ 应用源码包_1

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    VC++ MFC窗口缩放类函数

    8. **afx_msg LRESULT OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)**:这个成员函数用于非客户区的大小调整,如标题栏和边框。在自定义窗口样式时,可能需要重写此函数来实现自定义的缩放行为。...

Global site tag (gtag.js) - Google Analytics