GtkButton label updates - user-interface

I am designing a GUI using C, Glade, and Gtk.
I have some signals configured in glade to update the labels of various widgets, mainly GtkButton and GtkLabel. The overall functionality is that when a certain radio button is clicked, all button and labels change in response (language selection).
I am using the function gtk_label_set_label(...) in the widgets _draw() function and it works as expected (text changes, g_print occurs (once)).
gboolean on_lblMyLabel_draw(GtkLabel *label, gpointer *user_data) {
gtk_label_set_label(label, "custom text");
g_print("%s\n", "custom text");
return FALSE;
}
However, when I attempt the same from a button,
gboolean on_btnMyButton_draw(GtkButton *button, gpointer *user_data) {
gtk_button_set_label(button, "custom text");
g_print("%s\n", "custom text");
return FALSE;
}
The text does not update, but dissappears, and the g_print() statement prints forever (as if the draw is recursively calling itself).
Funnily, if I move the button code from _draw to _click, it works as expected, however, I need the GUI to redraw itself, so updating on click is impractical.
Is there a way, using _draw() to prevent this?
Is there a better way to do this?
thx!

Is there a way, using _draw() to prevent this?
No, and you shouldn’t be using the draw signal for this either. It has an entirely different purpose, and will be called each time a widgets redraws itself. That’s also the reason why your button is going into an infinite recursion: you changed its label so it figures it needs to be redrawn; that redraw leads to your callback being called, which again changes the label, etc etc
Is there a better way to do this?
Yes, and you mention it yourself already: make sure you do the logic of changing the widgets in the appropriate place (for example, on a click event), and let the GTK widgets take care of redrawing themselves.
Unless you’re doing something very exotic (like not running an event loop, which you automatically get with GtkApplication), this will all work fine.

Related

p5.js mousePressed works but doublePressed doesnot?

While programming my own minesweeper game, I have come to a stage(kind of final one) where I have to introduce the concept of Flags. Currently, I am using mousePressed() to open up any cell that might be a mine. But I cannot figure out a way how to flag any cell, as I tried to use doubleClicked() but it does not work in this case. Does anyone have any hint for this, or any built in p5.js tool that might simply flag a cell?
EDIT:
https://github.com/abj54/minesweeper
My code is in the above repo for anyone who might want to go through it. In terms of flag, it is a basic indicator of letting user guess which of the given cell may be a mine.
Listening to booth events on the same object is problematic because of the event change which is called for a dblclick:
mousedown
mouseup
click
mousedown
mouseup
click
dbclick
P5.js checks the click/dblclick event of the window so you should not use both functions (click and dblclick).
But you can use the click event with a Timeout to solve this problem.
var clicked=false, clickTimeout=300;
function mouseClicked(){
if(!clicked){
clicked=true;
setTimeout(function(){
if(clicked){
console.log("single click");
clicked=false;
//single ClickStuff
}
},clickTimeout);
}else{
clicked=false;
console.log("double click");
//double click Stuff
}
}
So you are waiting the in clickTimeout defined amount of Time if a second click is called and react to.

wxWidgets event focus textcontrol

I have another wxWidgets question regarding events and focus.
I have already looked at the tutorials and this old question here but I am still running into problems C++ Event (Focus) Handling
Basically I have a dialog with two wxTextCtrl elements and a Button.
What I would like to achieve is, that when I click on button it needs to tell me which of the two elements previously had the focus.
In the constructor of my Dialog I created all the elements and then connected them to the eventhandler like this: Ttop->Connect(TOP,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&UI_ADDENTRY::hasfocus);
Tbottom->Connect(BOTTOM,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&UI_ADDENTRY::hasfocus);
then there is the eventhandler that safes the id into focus
void UI_ADDENTRY::hasfocus(wxFocusEvent& event){
focus= event.GetId();
event.Skip();}
however when i try to access focus in the Button function it always tells me: 0 instead of TOP or BOTTOM / the ids that I gave the textcontrols
void UI_ADDENTRY::OnRecord(wxCommandEvent &event){
wxString tmp;
tmp << this->focus;
wxMessageBox(tmp);}
What am I doing wrong? is there another way of finding out which of the two textbox has been in focus last?
Thank you
The most fool proof way is to catch EVT_SET_FOCUS in your text controls and remember the last one that received it. This is not more difficult than what you are doing but should work without problems.
FWIW EVT_KILL_FOCUS can't, unfortunately, be consistently implemented on all platforms, in particular GTK+ doesn't give any information about the window focus is being lost to.
In think u mean event.GetWindow().GetId(). Though I'm not sure how ur casting from int to string.

Win32 App (Aero): Prevent dialog move

I've a dialog based Win32-app on Win7-Aero which only displays a dialog. The dialog should have a title bar. I don't want that the user can move the dialog on the screen.
I've no luck so far... handling WM_NCHITTEST, WM_SYSCOMMAND... setting SWP_NOMOVE.
What is the best way to achieve NoMove? I think DWM changes something on Win7.
You could do this by handling WM_WINDOWPOSCHANGING and when you see an attempted move, change the coordinates back to where they should be. E.g.
switch (uMsg)
{
case WM_WINDOWPOSCHANGING:
if (!(reinterpret_cast<LPWINDOWPOS>(lParam)->flags & SWP_NOMOVE))
{
reinterpret_cast<LPWINDOWPOS>(lParam)->x = g_iMyXCoord;
reinterpret_cast<LPWINDOWPOS>(lParam)->y = g_iMyYCoord;
}
return 0;
}
You would probably need to add some intelligence to this to distinguish between attempted moves by the user, and moves that your own program makes (or that the system makes if necessary - e.g. if a monitor disappears for instance).
Even though you say it doesn't work, I would have thought you could also do this by trapping WM_NCHITTEST and returning HTBORDER whenever HTCAPTION would have been returned - however you would have to do this by sub-classing the window rather than in the DialogProc (because you would need to call the default handler first and then process/change the return value). Same for WM_SYSCOMMAND (to catch moves the user attempts via the system menu).

Hiding a control in Windows

I can't figure out how to hide a child window (a control), more specifically a GroupBox and a PushButton. I thought ShowWindow() with SW_HIDE as the second parameter would do the job, but it simply doesn't work. Yet SW_SHOW works just fine. I have the correct window handle for both controls, so that's not the issue.
I googled and all I could find was people asking how to hide dialogs, not controls. Either that or MFC-based applications, which doesn't apply here.
I'm using pure Windows API, no MFC.
What am I getting wrong?
EDIT: More info: I'm writing some simple class wrappers for WinApi controls. The WindowsControl class has, along other methods, the following methods for showing and hiding the Control:
void Show() {
ShowWindow(this->_hWnd,SW_SHOWNOACTIVATE);
}
void Hide() {
ShowWindow(this->_hWnd,SW_HIDE);
}
Every control inherits from WindowsControl.
This image has the window layout so you understand exactly what I'm doing: http://i.stack.imgur.com/PHQnH.png
When the user clicks inside the "Chipset" Static control, it'll load information for a given Tile (which is stored in an array, but that's irrelevant). Depending on the setting, it'll hide the "Edit bitwall" button on the left and show the empty GroupBox behind it or viceversa.
Just to be clear this isn't something wrong with my windows api wrappers, I am getting the correct HWND. Though ShowWindow might not be able to be called from a Window Procedure that isn't the parent's (that'd be weird).
EDIT2: Using C++ with Visual Studio 2008, no MFC, no WTL, no CLR, no .NET
EDIT3: I'll post even more code so it's easier
Inside the static's window procedure, I handle WN_LBUTTONDOWN like this:
case WM_LBUTTONDOWN: {
...
update_tiledata(c, l)
void update_tiledata(GroupBox * c, ListView* l ) {
...
if (chp_copy.Tiles[selectedTile].Pass() == PT_BITWALL) {
c->Controls(CTL_BTNEDITBIT)->Show();
c->Controls(CTL_FRPHOLD)->Hide();
} else {
c->Controls(CTL_FRPHOLD)->Show();
c->Controls(CTL_BTNEDITBIT)->Hide();
}
update_edits();
}
The ommited code does nothing to affect the classes, as I said before, ShowWindow with SW_HIDE IS getting called, with the correct HWND, but nothing is happening.
A control in a Window or dialog can be hidden using
ShowWindow(hControlWin, SW_HIDE);
In a dialog you can retrive the controls window handle by calling
GetDlgItem(hDlg, < CtrlID >);
Typically you write something like:
ShowWindow(GetDlgItem(hDlg, 2), SW_HIDE);
It would be helpful if you give more information and some code: How did you create the controls? What language, compile and framework did you use?
I think the function call you want is EnableWindow I have used this before to disable a button on a form. You will need to get an handle to the Window (object) first though so you might want to use EnumChildWindows to iterate through all the controls to find the one you want.

Win32: How to custom draw an Edit control?

i need to implement the functionality of EM_SETCUEBANNER, where a text hint appears inside an Edit control:
The catch is that i cannot use version 6 of the Common Controls, which is what is required to get the Microsoft supplied implementation of a cue banner.
i've looked into simply changing the text of the edit control, and the font format to
Dark Gray Italic Text
but it will throw Change events (component wrapper provided by higher component library) that i can't find a way to avoid.
So i was instead going to custom draw the text, drawing the Cue Banner text when the control is unfocused and empty, and rely on default painting otherwise.
The Edit control doesn't nicely expose a custom drawing mechanism, like ListView, TreeView and others provide.
Other people have looked into it, but it seems to be an nearly impossible task:
From the way things are looking, I'll
have to handle the following
messages:
WM_ERASEBKGND, WM_PAINT (for obvious reasons)
WM_SETFOCUS, WM_KILLFOCUS (to prevent
the white bar from displaying --
described above)
WM_CHAR (to process and update the
text in the control)
And I also need to find a way to
display the caret in the control,
since I haven't found a way to allow
Windows to do that for me without also
painting the white bar I mentioned.
This is going to be fun. :rolleyes:
Given that the Windows Edit control was never meant to be custom drawn: does anyone know how to custom draw a Windows Edit control?
Note: i will also accept answers that solve my problem, rather than answering my question. But anyone else wanting to custom draw an Edit control, coming across this question, would probably like an answer.
Custom drawing an Edit control is essentially impossible. There are a few specialized cases were you are doing so little that can get away with it, but you risk breaking badly in the next revision of windows (or when someone runs your app on an older version, or via terminal services, etc).
Just taking over WM_PAINT and WM_ERASEBKGROUND aren't good enough, because the control will sometimes paint on other messages as well.
You are better off just writing your own edit control. I know that's a huge amount of work, but in the long run it will be less work than trying to hack your way into taking over all of the Edit controls' drawing code.
I remember back in the good old days when everyone use to subclass the button control to add color and graphics, etc. The thing is, one day I sat down and just wrote my own button window class. and it was LESS CODE than what we had in our source tree to subclass and custom draw the Windows button.
Create a window class of your own that looks like and empty edit control, that draws the cue text and shows a caret and has focus. Create the edit control also, but position it behind your window. (or leave it hidden)
Then when you get the first WM_CHAR message (or WM_KEYDOWN?). You put your window behind the edit conrol, give focus to the edit, and pass the WM_CHAR message on. From then on the edit control will take over.
You can listen to EN_CHANGE notifications from the edit control if you need to go back to showing your cue text when the edit gets empty. But I'd think that it would be fine to go back to the cue text only when the edit looses focus AND is empty.
Subclassing the EDIT control worked well for me - needed to display some formatting information to the user when editing object attributes (and some attributes could be multiple lines). The important thing, like Adrian said in his answer too, is to call the EDIT control's procedure before your own drawing. Calling it afterward or issuing your own BeginPaint/EndPaint (with return 0 or DefWindowProc) caused issues for me from the text not displaying at all, to it displaying only when resizing but not after editing, to leaving screen litter of the leftover caret. With that, I haven't had any issues regardless of the EDIT control's other repaint times.
Some setup:
SetWindowSubclass(attributeValuesEdit, &AttributeValueEditProcedure, 0, reinterpret_cast<DWORD_PTR>(this));
// Not only do multiline edit controls fail to display the cue banner text,
// but they also ignore the Edit_SetCueBannerText call, meaning we can't
// just call GetCueBannerText in the subclassed function. So store it as
// a window property instead.
SetProp(attributeValuesEdit, L"CueBannerText", L"<attribute value>");
The callback:
LRESULT CALLBACK AttributeValueEditProcedure(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
UINT_PTR subclassId,
DWORD_PTR data
)
{
...
case WM_PRINTCLIENT:
case WM_PAINT:
{
auto textLength = GetWindowTextLength(hwnd);
if (textLength == 0 && GetFocus() != hwnd)
{
// Get the needed DC with DCX_INTERSECTUPDATE before the EDIT
// control's WM_PAINT handler calls BeginPaint/EndPaint, which
// validates the update rect and would otherwise lead to drawing
// nothing later because the region is empty. Also, grab it from
// the cache so we don't mess with the EDIT's DC.
HDC hdc = (message == WM_PRINTCLIENT)
? reinterpret_cast<HDC>(wParam)
: GetDCEx(hwnd, nullptr, DCX_INTERSECTUPDATE|DCX_CACHE|DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
// Call the EDIT control so that the caret is properly handled,
// no caret litter left on the screen after tabbing away.
auto result = DefSubclassProc(hwnd, message, wParam, lParam);
// Get the font and margin so the cue banner text has a
// consistent appearance and placement with existing text.
HFONT font = GetWindowFont(hwnd);
RECT editRect;
Edit_GetRect(hwnd, OUT &editRect);
// Ideally we would call Edit_GetCueBannerText, but since that message
// returns nothing when ES_MULTILINE, use a window property instead.
auto* cueBannerText = reinterpret_cast<wchar_t*>(GetProp(hwnd, L"CueBannerText"));
HFONT previousFont = SelectFont(hdc, font);
SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, cueBannerText, int(wcslen(cueBannerText)), &editRect, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
SelectFont(hdc, previousFont);
ReleaseDC(hwnd, hdc);
// Return the EDIT's result (could probably safely just return zero here,
// but seems safer to relay whatever value came from the edit).
return result;
}
}
break;
Writing your own EDIT control (which I've actually done more than once, to partial degrees of completeness compared to the built-in one) is not much work if you do the bare minimum (maybe English only with basic caret support), but it's a LOT of work to get correct if you want caret navigation over complex scripts with variable sized clusters, selection over ranges, IME support, context menus with copy and paste, high contrast modes, and accessibility features such as text to speech. So unlike so many other answers, I recommend not implementing your own EDIT control merely for cue banner text.
Subclass the edit control. Handle WM_PAINT by first calling the original window procedure and then, if it's empty and not in focus, draw the cue text. Pass every other message to the original window procedure.
I've done this--it works. The problem the CodeGuru person had doesn't seem to apply to your situation. I believe he's trying to do more to the appearance. For performance, it looks like the edit control is doing some updates outside of WM_PAINT processing (probably for performance). That's going to make it nearly impossible to take complete control of the appearance. But you CAN draw the cue prompt.
And I also need to find a way to display the caret in the control,
since I haven't found a way to allow Windows to do that for me without
also painting the white bar I mentioned.
If you want to handle WM_PAINT by yourself without forwarding the message to the original windowproc of your superclass, you should not forget to call DefWindowProc. So that the caret will be drawn.
To avoid the white bar you should remove class brush with SetClassLongPtr.
And somehow keep your DC's clipping region to clip Edit controt's ExtTextOut outputs.
The white bar may be the result of OPAQUE option passed to ExtTextOut by Edit control.
Conclusion: Write your own control. No pain, no gain.

Resources