C++获取对话框控件的位置和大小

C++ Get the position and size of a dialog control

本文关键字:位置 获取 对话框 控件 C++      更新时间:2023-10-16

我使用的是Visual Studio 2015 C++,在.rc文件中定义了一个对话框:

IDD_SERIALCTRLDEMO_DIALOG DIALOGEX 0, 0, 313, 164
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "SerialCtrlDemo"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
LTEXT           "Serial Number:",IDC_STATIC,14,10,48,8
COMBOBOX        IDC_COMBO_SN,66,8,48,55,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT           "Baud Rate:",IDC_STATIC,135,10,37,8
COMBOBOX        IDC_COMBO_BR,176,8,48,55,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT           "Read:",IDC_STATIC,11,51,20,8
PUSHBUTTON      "Open",IDC_BUTTON_OPEN,242,7,50,14
LISTBOX         IDC_LIST_READ,11,62,23,76,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
EDITTEXT        IDC_EDIT_WRITE,11,34,237,14,ES_AUTOHSCROLL
PUSHBUTTON      "Write",IDC_BUTTON_WR,252,33,46,14
GROUPBOX        "",IDC_STATIC,7,0,294,25
GROUPBOX        "",IDC_STATIC,7,26,296,117
LTEXT           "",IDC_STATIC_INFO,11,150,287,8
CONTROL         "",IDC_SENSOR,"Static",SS_BLACKRECT,41,62,256,76
END
enter code here

我感兴趣的控件是图片框"IDC_SENSOR"(最后一个条目),它在/处定义为41,62256,76。但在屏幕上,比例是不同的,可能是由于动态对话框布局。所以我想知道对话框中该框的确切位置和大小,但我无法获得这些参数。

它用于的程序:

void CSerialCtrlDemoDlg::OnEventRead(char *inPacket,int inLength)
}
int x=0;

m_listboxRead.AddString(inPacket);      // display the incomming data in the 'Read' listbox
CString str;                    // display the # of data's in 'Info'
str.Format("%d bytes read",inLength);
m_staticInfo.SetWindowText(str);
CWnd *cWndSensor = GetDlgItem(IDC_SENSOR);  // show the fluctuation in the Picturebox 
CDC *pDC = cWndSensor->GetDC();
for (x = 0; x < 200; x++)
{
pDC->SetPixelV(x, 10, RGB(rand() % 255, 0, 0));
}
}

x<for循环中的200应该设置为图片框的宽度。

如何获取这些尺寸?

我希望这是足够的信息(?)。

你好,CJ。

我感兴趣的控件是picturebox"IDC_SENSOR"(最后一个条目),它在/处定义为41,62256,76。但在屏幕上,比例是不同的,可能是由于动态对话框布局。

是的,没错。对话框资源中的坐标是以DLU(对话框单位)指定的。您可以通过调用MapDialogRect函数将对话框单位转换为像素。

但这并不是你真正想要做的,因为你不想在代码中对对话框坐标进行硬编码。如果更改资源文件,则表示希望代码继续工作。

我想知道对话框中该框的确切位置和大小

您真正需要的是获得屏幕上控件的坐标,单位为像素。有两个专门为此设计的功能:

  • GetClientRect告诉您窗口在客户端坐标中的矩形。对于子窗口(如控件),左上角将始终为(0,0),右下角将告诉您宽度和高度
  • GetWindowRect告诉您屏幕坐标中的窗口矩形。这些是相对于虚拟屏幕的"绝对"坐标。与客户端矩形不同,窗口矩形还包括窗口非客户端区域的大小

您可能已经知道这一点,但这个矩形的宽度是通过从其右边界减去其左边界来确定的。类似地,通过从其下限减去其上限来确定高度。或者,如果使用MFC包装类CRect(它在任何地方都可以与RECT互换,包括在调用上述两个函数时),则可以只调用WidthHeight成员函数。

至于您的特定用例,由于您在子窗口本身上调用GetDC,因此您得到了一个客户端DC,并且您需要客户端坐标,因此您将调用GetClientRect。易于理解的除了你的代码是错误的。您正在获取DC并在WM_PAINT消息处理程序的外部绘制,这意味着您绘制的任何内容都会以任意间隔被擦除。所有绘图都应根据WM_PAINT消息进行。

在您的情况下,实现这一点的一个简单方法是为IDC_SENSOR控件设置SS_OWNERDRAW样式。这使父对话框负责绘制控件的内容。当需要绘制子控件时,它将接收WM_DRAWITEM消息。添加一个OnDrawItem处理程序并在其中绘制。作为参数传递的DRAWITEMSTRUCT将告诉您应该绘制的矩形(rcItem)。

最后,我应该注意到SetPixelV相当慢。如果它对你来说足够快,就忽略这条评论的其余部分。但是,如果在屏幕上绘制真的很慢,那么您应该考虑创建和缓存位图对象。绘制到该位图中,设置其各个像素,然后简单地将该位图闪电式传输到控件的设备上下文中。访问和操作屏幕外位图的各个像素要快得多。

我已经设法用GetClientRect:检索到了详细信息

void CSerialCtrlDemoDlg::OnEventRead(char *inPacket,int inLength)
{
int i = 0;
int j = 0;
int x = 0;
int y = 0;
int w = 100;
int h = 50;
RECT sensorRect;
CWnd *cWndSensor = GetDlgItem(IDC_SENSOR);
CDC *pDC = cWndSensor->GetDC();
cWndSensor->GetClientRect(&sensorRect);
x = sensorRect.left;
y = sensorRect.top;
w = sensorRect.right - x;
h = sensorRect.bottom - y;

for (i = 0; i < w; i++)    // this fills the picturebox (for test only)
{
for (j = 0; j < h; j++)
{
pDC->SetPixelV(i, j, RGB(rand() % 255, 0, 0));
}
}
}

因此,我将此问题标记为已回答!

我不太确定这是否是"正确"的方式,我缺乏这方面的经验。但它是有效的,然后应该还可以:)

我将按照建议使用位图,而不是(直接)绘制到图片框中。这确实更好,更容易使用。

我现在需要发现的是如何用位图以正确的方式更新对话框。正如Cody所说,这种绘图不应该在这个例程中完成,而是作为一个单独的OnDrawItem指令来处理。嗯,还有更多的东西要学。

感谢和问候,CJ