Invalidate() function not working - c++

I have a function that checks whenever a button check box i clicked
void CRisanjeDlg::OnBnClickedCheck1()
{
Invalidate(1);
}
And in the OnPaint method i have this code:
if(m_CheckBox1.GetState() ==1 )
{
CBrush brush;
CRect rect;
GetClientRect(rect);
brush.CreateSolidBrush(RGB(255,200,255));
rect.DeflateRect(0,0,500,0);
dc.Rectangle(rect);
dc.FillRect(rect, &brush);
}
I have a couple of other events, which trigger the OnPaint method, and if the box is checked, it draws what it has to draw.
It just doesn't work when i click the check box. The event is recognized, it's just that the Invalidate(1) does not work...
Any suggestions?
EDIT: When I uncheck the box, the function works fine. It seems the problem should be in the
if(m_CheckBox1.GetState() ==1 )
part.
EDIT2: True, the problem was in the mentioned if statement. This fixed it, don't know why. Would appreciate a further explanation.
m_CheckBox1.GetCheck() ==1

Try to use the debugger and see if you are coming inside your OnBnClickedCheck1 function

GetState returns a combination of states. Since the user is pressing on the button, you'll have BST_PUSHED and BST_FOCUS in addition to BST_CHECKED. It would have worked if you just tested for the single bit:
if ((m_CheckBox1.GetState() & BST_CHECKED) == BST_CHECKED)
Which can be simplified, since any non-zero value is true:
if (m_CheckBox1.GetState() & BST_CHECKED)

Related

QSlider postion changes only when minimazing app

I am using QSlider element in my app as a toogle switch. I took this project over from a colleage of mine who left. So far so good, except, that this switch has a black label around it. I can't really change the style and rework everything so, I am stuck with label and slider as switch.
I need to handle events from button clicked and button released. I do it like this-
bool CustomSlider::eventFilter(QObject *obj, QEvent *ev )
{
if (ev->type() == QEvent::MouseButtonRelease)
{
changeSliderValue();
}
if(ev->type() == QEvent::MouseButtonPress){
lastSaved = ui->horizontalSlider->value();
}
return QWidget::eventFilter(obj,ev);
And changeSliderValue()-
void CustomSlider::changeSliderValue()
{
int current = ui->horizontalSlider->value();
if(lastSaved==current){
if(current){
ui->horizontalSlider->setValue(0);
}else{
ui->horizontalSlider->setValue(1);
}
}
}
So, in short, if I click, it saves state of slider and when releasing it checks against saved state. I do it because QSlider has button pressed signal as well. I have put debug messages in my code and funny thing is debug messages fire. So my code works. If I call ui->horizontalSlider->value() I get the correct(changed) value But the slider is not moving. I have tried checking sequences, if it does not change value twice(it does not), I have tried calling repaint() and so far nothing works. Except if don't minimize(via minimize button) or click in different app(like web browser) and then I can see that slider moves to correct postion. I am completely confused. Has anyone encoutered something like this before?

MFC - Changing dialog item focus programmatically

I have a Modeless dialog which shows a bunch of buttons; some of these are customized to draw stuff with GDI.
Now, when the user clicks on a customized one under certain conditions, a message box appears to alert user of the error and this is fine.
The problem is that after accepting the Message Box (showed as MB_ICON_ERROR), everywhere I click in the dialog, I always get the error message as if the whole dialog send the message to the customized button and the only way to get rid this is to press tab and give the focus to another control.
This is a strange behaviour and knowing why happens wouldn't be bad, but a simple workaround for now should do the job.
Since the moment that is probably a matter of focus, I've tried to set it on another control (in the owner dialog) by doing:GetDlgItem( IDC_BTN_ANOTHER_BUTTON )->SetFocus();
and then, inside the customized control by adding:KillFocus( NULL );but had no results.
How should I use these functions?
Thanks in advance.
PS: if I comment the AfxMessageBox, the control does not show this bizarre behaviour.
EDITI'll show some code as requested.
// This is where Message Box is popping out. It is effectively inside the dialog code.
void CProfiloSuolaDlg::ProcessLBtnDownGraphProfilo(PNT_2D &p2dPunto)
{
// m_lboxProfiles is a customized CListBox
if(m_lboxProfiles.GetCurSel() == 0)
{
// This profile cannot be modified.
/*
CString strMessage;
strMessage.Format( _T("Default Profile cannot be edited.") );
AfxMessageBox( strMessaggio, MB_ICONERROR );
*/
return;
}
// Selecting a node from sole perimeter.
SelectNodo(p2dPoint);
}
Actually, the message is commented to keep the dialog working.
// This is inside the customization of CButton
void CMyGraphicButton::OnLButtonDown(UINT nFlags, CPoint point)
{
PNT_2D p2dPunto;
CProfiloSuolaDlg* pDlg = (CProfiloSuolaDlg*)GetParent();
m_pVD->MapToViewport(point,p2dPunto);
switch(m_uType)
{
case GRF_SEZIONE:
pDlg->ProcessLBtnDownGraphProfilo(p2dPunto);
break;
case GRF_PERIMETRO:
pDlg->ProcessLBtnDownGraphPerimetro(p2dPunto);
break;
}
CButton::OnLButtonDown(nFlags, point);
}
Since you are handling the button down event in the button handler for the custom control, you don't need to call the base class. Just comment out CButton::OnLButtonDown(nFlags, point).

Change cursor when hovering a child window

I have a window that asks for Login/Password with five child windows:
An editable one: Login
Another editable one: Password
An OK button
A "forgot your password" one
And a "Register" one.
Basically, when you click on either of the last two, you are sent to a website where you can perform the appropriate actions.
It's all fine and dandy, but I would love to know how it's possible to check (with messages I guess) if the mouse cursor is hovering over one of the two links, and if that's the case, to change it to a hand cursor.
I'd especially like to know how to detect it! I can figure out how to change the cursor afterwards with SetCursor and such!
EDIT: I actually found out that WM_SETCURSOR is a really easy message to handle. Basically, you check if the wParam is equal to the handle of the child window it's hovering over and voilĂ !
But I actually find the SetCursor to be a bigger issue.
Here's what I did:
The declaration of my cursors:
static HCURSOR hCursorHand;
static HCURSOR hCursorArrow;
The value is set here (in the handle for WM_CREATE):
hCursorHand = LoadCursor( NULL, IDC_HAND );
hCursorArrow = LoadCursor( NULL, IDC_ARROW );
And here's where I set it:
else if (msg == WM_SETCURSOR)
{
if ((HWND)wParam == hwndLinkFPasswd || (HWND)wParam == hwndLinkSignUp)
SetCursor(hCursorHand);
else
SetCursor(hCursorArrow);
}
I know the cursor is properly detected (thank you breakpoints), but it doesn't seem to do anything. The cursor stays an arrow...
So! As I said, I figured it out! (I just couldn't answer my question within the first 8 hours!)
Here's what I missed: (for anyone having the same problem)
else if (msg == WM_SETCURSOR)
{
if ((HWND)wParam == hwndLinkFPasswd || (HWND)wParam == hwndLinkSignUp)
{
SetCursor(hCursorHand);
return(TRUE);
}
}
I find the documentation on this API awful, so I hope my contribution will one day help someone in my situation! ;)

How to check if my window gets hidden/visible?

If i press the "show desktop" button in Windows7, my program will still think its not minimized, and if i press WIN+D while my program is focused, only then my program will catch this minimize command. How can i check for 100% sure that my program is visible or not?
Here is my main loop:
while(!done){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if(msg.message == WM_QUIT){
done = TRUE;
}else{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}else if(active){
render();
}
}
Edit3: Is this good? looks like its working:
case WM_WINDOWPOSCHANGED:
{
flags = ((PWINDOWPOS)lParam)->flags;
if((flags & 0x8000) && (flags & SWP_NOCOPYBITS) && (flags & SWP_FRAMECHANGED)){
active = !(flags & SWP_NOACTIVATE);
}
if((flags & 0x1000) && (flags & 0x0800) && (flags & SWP_NOMOVE) && (flags & SWP_NOSIZE)){
active = 1;
}
}
case WM_ACTIVATE:
{
active = !HIWORD(wParam);
return 0;
}
WM_ACTIVATE is sent when another window becomes active. When you say show desktop, no other window becomes active, so technically, your app is still active, even though it has been minimized.
You probably want to watch for WM_WINDOWPOSCHANGED. You can look at the flags to see what type of position event it was, or you can check IsIconic and IsWindowVisible whenever the window position changes.
There are a variety of potential functions that may get you the information you need depending on exactly what you want to do:
GetForegroundWindow() : Gets the window the user is currently "working" with. You could use this if you only wanted to draw things when a user is using your application but not another one.
GetActiveWindow() : Returns the active window within the calling thread which is probably not what you want. This might be useful if you wish to enable/disable drawing depending on which window was active within your own application.
GetFocus() : Returns the window with the current keyboard focus in the calling thread. Probably not what you want and use GetForegorundWindow() instead.
IsWindowVisible(): Returns whether the show/hide flag of the window is set to visible. This doesn't actually tell you whether the window is actually visible on the screen.
GetTopWindow(): Tells you the highest window in the z-order but not whether it actually has the focus/foreground. It may be possible for your window to be focused/activate/foreground but not have the highest z-order (I think anyways).
From your comments, however, you seem to actually want to see if there is at least one pixel of your window actually visible on the screen. For that I would probably use the technique mentioned in this SO question using the strangely named GetRandomRgn() although a simpler check may be to use GetClipBox() and check the return code for NULLREGION.
With Windows 8/10, there's another window visibility flag which is separate from IsWindowVisible. Check DwmGetWindowAttribute and the DWMWA_CLOAKED attribute.
Additionally, windows can be semitransparent, and GetLayeredWindowAttributes can tell you what the alpha level of a window is.
IsWindowVisible tells you if your window is visible. GetTopWindow tells you if it is the uppermost one in the Z order.
Try WM_ACTIVATEAPP.
wParam will be false if a window from any other app is getting focus. This includes pressing the "show desktop" button.

QWinWidget Inside MFC Dialog Not Repainting or Responding to Tab/Arrow keys

I am using a QWinWidget inside of an MFC dialog and the QWinWidget is not drawing itself correctly and it is not handling keyboard input correctly.
Repainting [Unsolved]
Within the QWinWidget, I have a QTableWidget. When I scroll the QTableWidget, it does not redraw itself until I stop scrolling, at which point it redraws everything. Similarly, I can type into cells in the QTableWidget and the control is not updated until I force it to re-update by scrolling up or down (it re-updates when the scrolling stops).
Since this QWinWidget is housed in an MFC CDialog, I tried overriding the CDialog's OnPaint method and only call the QWinWidget::repaint method, however this has the opposite problem where now only the QWinWidget is updated and the CDialog is never redrawn, resulting in artifacts. If I call QWinWidget::repaint and CDialog::OnPaint, the result is the same as not overriding the OnPaint method. Has anyone ever seen this problem or know how to resolve it?
Keyboard Input [Solved]
None of the controls within the QWinWidget respond to the tab key or arrow keys correctly. The tab/arrow keys simply skip over the entire QWinWidget (and all child controls). Even if I click inside the QWinWidget and select a control, the next time I press the tab key, it skips the focus completely out of the entire QWinWidget.
I noticed that the QWinWidget has two functions, QWinWidget::focusNextPrevChild and QWinWidget::focusInEvent and both of them have a comment header saying "\reimp". Am I supposed to override these functions in order to get correct tab functionality? If so, how can these functions be implemented for correct tab functionality.
I have fixed the keyboard input issue. The QWinWidget class needed some changes:
in the QWinWidget::init method, the WS_TABSTOP must be added to the window style:
SetWindowLong(winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP);
Also, the QWinWidget::winEvent method needs to respond to the WM_GETDLGCODE to let Windows know that it is interested in receiving key/tab inputs. I had to add this if block:
if(msg->message == WM_GETDLGCODE)
{
*result = DLGC_WANTARROWS | DLGC_WANTTAB;
return(true);
}
I am still working on getting the widget to paint properly.
I don't know about whether you need to reimplement the focusNextPrevChild() and focusInEvent() functions, but I do know that the "\reimp" in the comment header is part of Qt's documentation generation, which merely specifies that the function was a reimplementation of another function in a parent class.
Thanks! It works for me! I have fixed an arrow keys navigation issue for a QTableView inside a QWinWidget.
I am using Qt5.3.0 and qtwinmigrate 2.8.
The QWinWidget::nativeEvent method needs to be modified.
#if QT_VERSION >= 0x050000
bool QWinWidget::nativeEvent(const QByteArray &, void *message, long *result)
#else
...
{
...
if (msg->message == WM_SETFOCUS) {
...
} else if (msg->message == WM_GETDLGCODE) {
*result = DLGC_WANTALLKEYS;
return true;
}
return false;
}
No idea about the keyboard input, but concerning the repainting: have you tried calling QWinWidget::repaint() in the CDialog's OnPaint method AFTER calling the CDialog::OnPaint()?