[英]C++ Get the position and size of a dialog control
I'm using Visual Studio 2015 C++ and have a dialog box defined in an .rc-file: 我正在使用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
The control I'm interested in is the picturebox "IDC_SENSOR" (last entry), which is defined at/as 41,62,256,76. 我感兴趣的控件是图片框“ IDC_SENSOR”(最后一个条目),其定义为41,62,256,76。 But on screen that proportions are different, probably due to the Dynamic Dialog Layout.
但是在屏幕上,比例可能有所不同,这可能是由于“动态对话框布局”所致。 So I want to know the exact position and size of that box whithin the dialogbox, but I cannot get those parameters.
因此,我想知道对话框中该框的确切位置和大小,但是我无法获取这些参数。
The procedure which it is used in: 它用于以下过程:
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));
}
}
The x<200 in the for-loop should be set to the width of the picturebox. for循环中的x <200应该设置为图片框的宽度。
How can I get those dimensions? 如何获得这些尺寸?
I hope this is enough info(?). 我希望这是足够的信息(?)。
Greetings, CJ. 问候,CJ。
The control I'm interested in is the picturebox "IDC_SENSOR" (last entry), which is defined at/as 41,62,256,76.
我感兴趣的控件是图片框“ IDC_SENSOR”(最后一个条目),其定义为41,62,256,76。 But on screen that proportions are different, probably due to the Dynamic Dialog Layout.
但是在屏幕上,比例可能有所不同,这可能是由于“动态对话框布局”所致。
Yes, that's correct. 对,那是正确的。 Coordinates in dialog resources are specified in DLUs (dialog units).
对话框资源中的坐标以DLU(对话单位)指定。 You can convert dialog units into pixels by calling the
MapDialogRect
function. 您可以通过调用
MapDialogRect
函数将对话框单位转换为像素。
But that's not really what you want to do here, because you don't want to hard-code the dialog coordinates in your code. 但这并不是您真正想要的,因为您不想在代码中对对话框坐标进行硬编码。 If you change the resource file, you want your code to continue to work.
如果更改资源文件,则希望代码继续工作。
I want to know the exact position and size of that box whithin the dialogbox
我想知道对话框中该框的确切位置和大小
What you really need is to obtain the coordinates of the control on the screen, in pixels. 您真正需要的是获取屏幕上控件的坐标(以像素为单位)。 There are two functions specifically designed for that purpose:
为此专门设计了两个功能:
GetClientRect
tells you the window's rectangle in client coordinates. GetClientRect
告诉您客户端坐标中窗口的矩形。 For a child window, such as a control, the upper-left corner will always be (0, 0), and the lower-right corner will tell you the width and height. GetWindowRect
tells you the window's rectangle in screen coordinates. GetWindowRect
告诉您屏幕坐标中的窗口矩形。 These are "absolute" coordinates, relative to the virtual screen. You probably already know this, but the width of this rectangle is determined by subtracting its left bound from its right bound. 您可能已经知道这一点,但是此矩形的宽度是通过从其右边界减去其左边界来确定的。 Similarly, the height is determined by subtracting its top bound from its bottom bound.
类似地,通过从其底部边界减去其顶部边界来确定高度。 Or, if you use the MFC wrapper class,
CRect
(which is interchangeable everywhere with RECT
, including when calling the two above functions), you can just call the Width
and Height
member functions. 或者,如果使用MFC包装器类
CRect
(可在所有地方与RECT
互换,包括调用上述两个函数时),则可以仅调用Width
和Height
成员函数。
As for your particular use-case, since you're calling GetDC
on the child window itself, you're getting a client DC, and you would need client coordinates, so you would call GetClientRect
. 至于您的特定用例,由于您是在子窗口本身上调用
GetDC
,因此您将获得一个客户端DC,并且需要客户端坐标,因此您将调用GetClientRect
。 Simple. 简单。 Except that your code is wrong.
除了您的代码是错误的。 You are obtaining a DC and painting outside of a
WM_PAINT
message handler, which means that anything you paint is subject to being erased at arbitrary intervals. 您将在
WM_PAINT
消息处理程序之外获得DC和绘画,这意味着您绘画的任何内容都会以任意间隔被擦除。 All drawing should be done in response to a WM_PAINT
message. 应响应
WM_PAINT
消息完成所有绘图。
A simple way of accomplishing this in your case would be to set the SS_OWNERDRAW
style for your IDC_SENSOR
control. 在您的情况下,完成此操作的一种简单方法是为
IDC_SENSOR
控件设置SS_OWNERDRAW
样式。 This puts the parent dialog in charge of drawing the control's contents. 这使父对话框负责绘制控件的内容。 It will receive
WM_DRAWITEM
messages when the child control needs to be drawn. 当需要绘制子控件时,它将接收
WM_DRAWITEM
消息。 Add an OnDrawItem
handler and do your drawing in there. 添加一个
OnDrawItem
处理程序并在其中进行绘图。 The DRAWITEMSTRUCT
passed as a parameter will tell you the rectangle into which you should draw ( rcItem
). 作为参数传递的
DRAWITEMSTRUCT
将告诉您应绘制到的矩形( rcItem
)。
Finally, I should note that SetPixelV
is quite slow. 最后,我应该注意
SetPixelV
相当慢。 If it's fast enough for you, just ignore the rest of this comment. 如果速度足够快,请忽略此注释的其余部分。 But if drawing on the screen is really slow, then you should consider creating and caching a bitmap object.
但是,如果在屏幕上绘制的速度确实很慢,则应考虑创建并缓存位图对象。 Draw into that bitmap, setting its individual pixels, and then simply blit that bitmap onto your control's device context.
绘制到该位图中,设置其单个像素,然后只需将该位图blit到控件的设备上下文中即可。 Accessing and manipulating the individual pixels of an offscreen bitmap is much faster.
访问和处理屏幕外位图的各个像素要快得多。
I've managed to retrieve the details with GetClientRect: 我设法用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));
}
}
}
So I mark this question as answered! 因此,我将此问题标记为已回答!
I'm not quite sure if this is the 'correct' way, I'm lacking the experience for that. 我不太确定这是否是“正确”的方法,我缺乏经验。 But it works, and then it should be fairly ok :)
但这有效,然后应该还可以:)
Instead of drawing (directly) into the picturebox, I'm gonna use a bitmap as suggested. 与其(直接)画入图片框,不如我建议使用位图。 Thats indeed better and easier to work with.
那确实更好,更容易使用。
What I now need to discover is how to update the dialogbox the proper way with that bitmap. 我现在需要发现的是如何使用该位图以正确的方式更新对话框。 As Cody stated such drawing should not be done whithin this routine, but handled as a separate OnDrawItem instruction.
正如科迪所说,这种绘制不应在此例程中完成,而应作为单独的OnDrawItem指令进行处理。 Hmm, more to learn.
嗯,还有更多要学习的。
Thanx and greetins, CJ Thanx和greetins,CJ
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.