Aid with design issue? - c++

In my game, I have a panelA that has checkboxes to toggle panels in panelA's parent. It also has a Leave button which needs to make a call to the scene manager that only PanelA's parent is aware of.
I've thought of:
Making a listener just for this
Have the parent make the PanelA and make its children so it has
access to them and can receive action events from them
Neither of these feel that clean. Would there be a better way?
My game uses a gui system that I made. Sending events up to the parent wouldn't work because the parent does not know which gui components it's looking to handle.
Thanks

It's a bit hard to know without knowing the design of your system, but basically you don't want to change checkboxes in the panel, but you want to change the state and have those checkboxes reflect the state.
Say you want to check a box for Vertical Blanking in your main-panel. Do do not want to do this
parent->waitForVerticalBlankCheck.Checked=true
instead you want this
renderingConfiguration->isVerticalBlankEnabled=true;
and in your "main panel"
if(renderingConfiguration->isVerticalBlankEnabled)
waitForVerticalBlankCheck.Checked=true;
Uhm.. very pseudocody, but hopefully you get the idea :)

Related

QComboBox::showPopup() steals focus from its QLineEdit

In order to create a QComboBox that can filter its values list when typing in it, I attached a slot to the QComboBox's editTextChanged-event, to open its list view popup when the user starts typing. This is done like so:
void SearchableComboBox::slotEditing(QString in_text)
{
this->showPopup();
}
Unfortunately, this immediatly steals the focus from the QLineEdit and I can't type anymore.
Calling lineEdit()->setFocus() makes no difference, and I don't want to grabKeyboard() since this creates a whole other world of pain.
Any recommendations?
This isn't really a combobox then, more of a completion listview for a lineedit. I implemented exactly that in ruqola (KDE client for rocket chat), you can see the source code at https://lxr.kde.org/source/network/ruqola/src/widgets/common/completionlistview.cpp. Notice the little dance with the focus proxy thing:
setFocusPolicy(Qt::NoFocus);
textWidget->setFocusPolicy(origPolicy);
setFocusProxy(textWidget);
and the long method slotCompletionAvailable() for positioning the completion popup at the right place...
Use the Focus Proxy method for this purpose. See https://doc.qt.io/qt-5/qwidget.html#setFocusProxy
With this the pop-up would relay its inputs to the lineedit.
In your case you could try something like
this->setFocusProxy( this->lineEdit() );
But maybe you should read how to use a QCompleter. This would provide Autocompletion while typing and is maybe also useful for you.

How to avoid ugly overlap with too many dockwidgets in QMainWindow?

In our application, we have a variable number of dockwidgets because some of them are added by plugins that are loaded at runtime. Not all dockwidgets need to be visible at the same time necessarily. This depends strongly on what the user is working on and what plugins are active.
However, if too many dockwidgets are added programmatically with addDockWidget(...), they start to overlap each other (not in terms of tabs, but in terms of content of one being painted on the area of a different one, which obviously looks broken).
The user can move the dockwidgets to dockareas that still have space left, but the layout/main window successfully prevents (untabbed) re-addition to the "crowded" dockarea.
We do allow tabbed docks to allow the user to arrange the dockwidgets a required, but we don't want to enable QMainWindow::ForceTabbedDocks since this would constrain the number of simultaneously visible dockwidgets too much (one per dock area).
How can I prevent this or better control how dockwidgets are added?
Not answering your question directly but it might be worthwhile to actually forget about Qt and actually think of how the whole interaction should work. What are the user expectations? What should actually happen if 10 different plugins become active? Should they be docked or should they be floating or should they become pin-able docking windows with initial state as a small button on the MainWindow edges? I think once you do that ground work and come up with user interface mock-ups, you can then start looking at Qt and figure out if Qt provides a direct way to develop that interface and if not what additional components you will need to develop to get that interface working.
From my own experience, I had developed a similar interface long back but in MFC. The way we did it was that some of the docked windows were deemed to be must have and they would come up as docked. Then there were a set of windows that didnt need to be visible always but should be quickly available and their initial state was as hidden pin-able dock window which meant they came up as buttons on the MainWindow edge. Finally there was a third set that was not required by the user always and could be called in from File->View Menu. Once the user made it visible, the user typically would assign it to one of the first two groups or keep it afloat. This whole configuration was saved in a config file and from there onwards whenever the plugin was loaded/became active the last used state of the associated docking window was used. It though involved quite a bit of extra work but the end result was to the satisfaction of all users.
Have you tryed setDockOptions(QMainWindow::AllowNestedDocks)? I can't test it now but it may help.
By default, QMainWindow::dockOptions is set to AnimatedDocks | AllowTabbedDocks so you would want something like
setDockOptions(QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks | QMainWindow::AllowTabbedDocks)
EDIT:
If you are having too many problems, you may be going about this the wrong way. Instead of using docks, you may want to try using QMdiArea with QMdiWindow. This may not work for your program, but its something to think about.
This is the solution I tried:
I created in QTCreator an empty project with a window, a minimalistic menu labelled "New Dock" and a DockWidget named dockWidget
This is the triggered() handler for my menu item:
void MainWindow::on_actionNew_Dock_triggered()
{
QDockWidget* w = new QDockWidget("Demo", ui->dockWidget);
this->addDockWidget(Qt::LeftDockWidgetArea,w);
this->tabifyDockWidget(ui->dockWidget,w);
}
tabifyDockWidget(QDockWidget* first, QDockWidget* second) is a QMainWindow method that stacks the second dockwidget upon the first one. Hope it helps...

How to make Qt delegate editors 'sticky'

I'm migrating an application from a homegrown UI to Qt. One of the most important controls is the property panel, which takes an object that implements my reflection API's interface and spits out a dialog box containing editors for all the properties.
I've written an implementation of QAbstractItemModel for my property system and I've written a few handlers for various types inside of a QTableView. I've also written a QItemDelegate to create editors for the properties.
The trouble is that I'd like the editors to hang around, rather than be strictly popups. This is so that they can handle the rendering of the property, require less clicks to operate and also not disappear as soon as something else gets the focus, such as my colour button - the editor (which has the slots listening for colour changes) disappears as soon as the colour picker dialog appears, which means that nothing is then listening for changes.
I can't find any options for making the editors persist. Am I barking up the wrong tree here or is there a more appropriate way of doing this? I've tried to do things the 'Qt' way but I'm already hitting brick walls.
Thanks,
There is the QAbstractItemView::openPersistentEditor() method.

How to mix C++ and external buttons on seperate window?

I want to make a C++ button on Start>Run i.e but when I do it will not do signalled event?
Im sorry I have seen that you do not get the question.
Ok basically when you create a button with CreateWindowEx(); I want to do that but put on a different window with SetPArent which I have already done now the button does not work so I need my program to someone get when it is clicked from the Run window as example!
And yes you have it, but it's not making the button is the problem it's getting when it's clicked with my program since it does not belong to it anymore!
You need to apply the ancient but still-supported technique known in Windows as subclassing; it is well explained here (15-years-old article, but still quite valid;-). As this article puts it,
Subclassing is a technique that allows
an application to intercept messages
destined for another window. An
application can augment, monitor, or
modify the default behavior of a
window by intercepting messages meant
for another window.
You'll want "instance subclassing", since you're interested only in a single window (either your new button, or, the one you've SetParented your new button to); if you decide to subclass a window belonging to another process, you'll also need to use the injection techniques explained in the article, such as, injecting your DLL into system processes and watching over events with a WH_CBT hook, and the like. But I think you could keep the button in your own process even though you're SetParenting it to a window belonging to a different process, in which case you can do your instance subclassing entirely within your own process, which is much simpler if feasible.
"Superclassing" is an alternative to "subclassing", also explained in the article, but doesn't seem to offer that many advantages when compared to instance subclassing (though it may compared with global subclassing... but, that's not what you need here anyway).
You'll find other interesting articles on such topics here, here, and here (developing a big, rich C++ library for subclassing -- but, also showing a simpler approach based on hooks which you might prefer). Each article has a pretty difference stance and code examples, so I think that having many to look at may help you find the right mindset and code for your specific needs!
OK, I'll do my very best - as I understand you, you're trying to inject a button into some existing window. That meaning: Your tool creates a button in some window that does not belong to your application. Now, you want to be notified when that button is pressed. Am I correct so far?
To be notified about the button being pressed, you need to get the respective window message, which will only work if you also "inject" a different WndProc into the window. Actually I have no idea how that should work, but I faintly remember functions like GetWindowLong and SetWindowLong. Maybe they will help?
EDIT
I've searched MSDN a little: While you can get the address of a window's WndProc using GetWindowLong, you can not set the WndProc using SetWindowLong on Windows NT/2000/XP (and up I suppose). See here (MSDN).
So what you could do is install a global message hook that intercepts all window messages, filter those for the window you've injected the button into and then find your message. If you have trouble with this, however, I'm the wrong person to ask, because it's been years ago since I've done anything like that, but it would be stuff for a new question.
EDIT 2
Please see Alex Martinellis answer for how to define the hook. I think he's describing the technique I was referring to when I talked about defining global message hooks to intercept the window messages for the window you injected your button into.

Prevent views stealing focus/setting focus to a view

I have an MFC sdi app that uses a splitter window to contain a tree control alongside the main view showing the data.
When the user selects something in the tree, that view keeps focus until the user deliberately clicks in the main data window. This means that any toolbar buttons associated with the main view are disabled.
Is there any way to programmatically switch focus back to the main view after the user has clicked the tree control? Or am I doing something fundamentally wrong using a CSplitterWnd and 2 views?
You don't want to bring the focus back to the other view as soon as someone clicks the tree: It would make your app unusable. e.g. It would prevent users from navigating through the tree using the keyboard since the tree would never keep the focus long enough.
I you really want the toolbar to keep reflecting the state of your 2nd view (I'm not sure it's a good idea), you have a few options. Make your pick. 2 come to mind:
Your tree view should NOT be a CView. Use a simple CTreeCtrl. Not very nice because it kind of break the doc/view paradigm (e.g. no more tree's OnUpdate() called whenever an UpdateAllViews() is called).
Prevent the tree from becoming the active view. To do so:
2.a. When you view gets the focus (OnSetFocus()):
STATIC_DOWNCAST(CFrameWnd, AfxGetMainWnd())->SetActiveView(pTheOtherView);
2.b. Derive a CMySplitterWnd class from CSplitterWnd, then override CMySplitterWnd::SetActivePane() to prevent it from setting the treeview as the active view.
In all cases, welcome to the wonderful world of MFC internals where diving into the source code is the mandatory daily sport ;-)