Get pointer to registered field in the wizard - qt

Can I get access to the widget of registred field in the QWizardPage?
QLineEdit* fld = new QLineEdit;
// register
registerField( "test", fld );
....
// Somewhere in wizard
QLineEdit* field = ?

You can assign a unique name to the widget, then find it in the wizard's children. Recall that widgets are QObjects. This technique applies to all QObjects and is not specific to the wizard, or even to widgets.
char const fieldName[] = "MyCoolField";
fld->setObjectName(fieldName);
...
QLineEdit * field = wizardPage->findChild<QLineEdit*>(fieldName);
if (field) {
...
}

It looks like QWizardPage isn't really designed to do this — which is why the field function just returns the widget's contents, not a pointer to it.
Looking at the source code for QWizardPage::registerField, getting to the fields is going to be nasty: they're stored in the QWizardPrivate class, which is used to isolate the private implementation of the QWizard class from its public interface (see Qt's D-Pointer write-up for more information about this approach).
I don't recommend trying to figure out how to actually expose the internals of QWizardPrivate to your own code. That's because the whole reason QWizardPrivate exists is to allow Qt to completely change the private data and implementation in a minor release, without affecting compiled code — it's a moving target.
The simplest solution is to store your own pointer to the QLineEdit externally, if at all possible. For example, if you're subclassing QWizardPage, try creating a "shadow" field map of your own.

Related

How should a Qt-based preferences panel broadcast that a pref has changed?

I am trying to design a preferences panel for my multidocument app. When a given pref changes – font size, say – all of the document windows should immediately update to reflect the new pref value. I don't want to construct the preferences panel up front, for all the document windows to connect to, because it contains a QFontComboBox that takes more than a second to set itself up (ouch); that's not a price I want to pay at startup. So then, my question is: what is an elegant design for the prefs panel to let all the document windows know about the change? In Cocoa, which I'm more used to, I'd use NSNotification to broadcast a notification from the prefs panel that all the document windows could observe; that provides the loose coupling required (since objects can add themselves as observers before the broadcaster exists).
Two approaches occur to me so far:
Loop through topLevelWidgets, do a dynamic cast to my document window class, and for all the document windows I thereby find, just call a hard-coded method on them directly.
Make a second class, PreferencesNotifier, that is separate from the UI object that takes so long to load, and construct a singleton object of this class at startup that all of the document windows can connect themselves to. When the preferences panel eventually gets created, it can send signals to slots in PreferencesNotifier, which will then call its own signals to notify the connected document windows.
Neither seems quite as elegant as NSNotification, and I'm wondering if I'm missing something. Thanks for any tips.
First thing, do not try to copy patterns, like Cocoa's NSNotification/NotificationCenter, to other frameworks (or languages, or...). There are various ways to send messages and generally each framework has picked one. Trying to use the one method that was picked by the framework you are using will lead to the most elegant solutions.
If you really want to, you could implement your own set of classes that will do exactly what NSNotification does. It will feel more elegant to you, but only because you are used to using Cocoa. It will feel odd to every other Qt developer. Also, this solution will require you to write a lot of code as you will not be able to leverage all the features of Qt.
The first solution you are suggesting is a bit ugly and looks more like a hack than anything.
What I do, when I have to handle preferences in a program, is something similar to your solution 2. I create a class that is responsible for handling all settings: read/write setting file, change setting, set default values, etc. Generally this class is a singleton. This class has very limited access to other parts of the program, and generally no access at all to the UI. Each components that needs to access the preferences will use this class. If you do it properly (e.g. use Q_PROPERTY), this class can even be accessed by QML, if you ever need to use Qt Quick.
class Settings: public QObject {
Q_OBJECT
Q_PROERTY(bool showX READ showX WRITE setShowX NOTIFY showXChanged)
public:
bool showX() const { return m_showX; }
void setShowX(bool show) {
if (show == m_showX)
return;
m_showX = show;
emit showXChanged(m_showX);
}
signals:
void showXChanged(bool);
public slots:
void save() const; // Save to disk
void load(); // Load from disk
private:
QSettings m_settings; // Handle load/save from/to disk
bool m_showX;
};
class Window {
Window() {
...
m_widgetX->setVisible(settings->showX());
connect(settings, &Settings::showXChanged,
this, [this](bool show) { m_widgetX->setVisible(show); }
);
...
}
};
class PrefWindow {
PrefWindow () {
...
ui->checkBoxShowX->setChecked(settings->showX());
...
}
private slots:
void on_saveButton_clicked() {
settings->setShowX(ui->checkBoxShowX->checked()):
settings->save();
}
};

Application GUI state saving in Qt

What is an optimal and an appropriate way to save the state of a Qt GUI so I get the same state I had back when I closed the application ?
By state I mean : current indexes (for combo box ...), color palette, widgets positions... right before closing the application
You can use the QSettings class.
Simple use of QSettings class (code inspired from Qt's documentation):
In the main-window of your application code member functions that saves and restore the settings:
void MainWindow::writeSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize(400, 400)).toSize());
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
Call those 2 functions from the MainWindow constructor and from the closeEvent override, like this:
MainWindow::MainWindow()
{
// code from constructor
//...
readSettings();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
//optional check if the user really want to quit
// and/or if the user want to save settings
writeSettings();
event->accept();
}
The direct answer requires specific elaborated design for your code and not really a short Qt question or even the question specific to Qt. That is about C++ which is not the VM-based language that assists with serializing the state of program code to data. Having all objects serializable we can then attempt to apply certain C++/Qt classes/techniques.
This task is much easier to accomplish with languages like Java, though. And with C++/Qt you have to routinely make serialize-able / serialize / restore everything that is running in your code and still no guarantee that works as long as the context is not fully captured. This task is not easy for sure and makes sense only in specific application.
The most you can get directly from Qt is to save/restore QMainWindow and other independent widgets geometry (position/size):
saveGeometry
restoreGeometry
... and that solution is still somewhat incomplete or you may/not use QSettings for the storage.
I use QSettings for this. With routines similar to Zlatomir's.
For each window I have in the project I use a different section in QSettings and have readSettings() and writeSettings() in the source for each window.
Anything on the form that I want to persist I have to explicitly save and recall. In the case of a QComboBox it would be something like:
QSettings settings("Organisation", "MySoftware");
settings.beginGroup("WindowNumberTwo");
settings.setValue("ComboIndex", combobox->currentIndex());
// save more values here
// ...
settings.endGroup();
I don't know of a built in way to persist your window states - it has to be don't value by value.

Calling QStandardItem mimeData() method

In my app I have a QTableView and a QTreeView. I need to drag from the table view and drop in the tree view. I had this working, but I reworked the app so that the GUI elements were created in C++ and this this has stopped working.
I can pick up an item from the table and drop it on the tree - all looks fine. However, the table model's mimeData() method is not called, so the dropped data is incomplete.
How do I get the drag drop operation to call the mimeData() method?
The tables' model is based on a QStandardItemModel.
Had a similar issue with my code. Make sure you override the mimeData properly. For example, some examples show the prototype as:
QMimeData *mimeData(const QList<QTreeWidgetItem *> &items) const;
while the correct prototype is:
QMimeData * mimeData(const QList<QTreeWidgetItem *> items) const;
(note the missing reference in front of items). And if you implement it incorrectly, you're not overriding the mimeData() but implementing another mimeData() function.
An easy check to make sure you're doing it right is to declare a function you want to override, but change its return type from QMimeData* to bool, such as:
bool mimeData(const QList<QTreeWidgetItem *> items) const;
If you are overriding a correct function, your code will not compile due to conflicting return type (you're not allowed to override only the return type). If your code compiles fine, you are not overriding anything but instead declaring a new function. Check the function signature.

What is an appropriate place to initialize QWidgets?

What is the best way (place) to initialize QWidgets, when you add them programmatically?
I can think of ways to do it:
1) Create instances in the definition file and then initialize them in the initializer list. This seems to be the right way, but it becomes kind of sloppy the more QWidgets you need to add to the Window.
class SomeWindow : QDialog{
...
private:
QLabel label1;
QLabel label2;
...
}
SomeWindow::SomeWindow(...) : QDialog(...),
label('label1 text'), label('label2 text')
{
...
layout.addWidget(&label1);
layout.addWidget(&label2);
...
}
2) Coming from C# I tend to like this, but it seem to generate memory leak...
SomeWindow::SomeWindow(...) : QDialog(...)
{
QLabel* label1 = new QLabel('label1 text');
QLabel* label2 = new QLabel('label2 text');
...
layout.addWidget(label1);
layout.addWidget(label2);
...
}
Is there a better way to do this that I'm missing?
I appologize for the newbie question.
Qt use his own system to delete parent-children QObject derived classes. When you delete object, all children are deleted too.
With the first code, you have 2 destructions (in destructor of SomeWindow and with QObject system), then this code is illegal (only with Qt ; with C++ standard code, it's good)
With the second code, labels are delete by QObject system, you don't have memory leak. No need to keep pointer on objects.
#Jairo
Setting parent in constructor is not the only way to add children to objects. In particular, here, QLayout::addWidget reparent objets (if layout is correctly child of object)
#msgmaxim
Be carefull, layout must not be local variable in constructor
An advantage to having pointers to widgets in the headers, rather than the actual objects, is that you don't need to include all the headers for the widgets, but just forward declare them. This increases compilation time, which can be considerably noticeable in large projects.
In addition, if you have a dialog and are just adding a lot of widgets, such as a QLabel, you can make the code neater by doing this in the implementation: -
layout.addWidget(new QLabel('label1 text'));
layout.addWidget(new QLabel('label2 text'));
layout.addWidget(new QLabel('label3 text'));
layout.addWidget(new QLabel('label4 text'));
As has been mentioned, Qt's parent system will take care of cleaning up the widgets when their parent is deleted.
Of-course, if you want to change a property, such as the text, you'd then need to find the widget from the layout's children, but often QLabel, as its name implies, just labels an item and its properties aren't changed.
Two ways are good in order to initialize a new widget.
First case you have labels as objects. So when SomeWindow is destroyed, they will be destroyed automatically too. Remember, if you have pointer to widgets instead objects, you will need (and can) to delete the labels into destructor of dialog.
SomeWindow::~SomeWindow()
{
delete label1;
label2.deleteLater(); // A safer way to delete a widget. Thread-safe.
}
And second case there will be a memory leak because you have no way to delete the widget into destructor. But if you define a parent for labels, they will be delete when parent is delete too. Take a look to QWidget documentation.
If parent is 0, the new widget becomes a window. If parent is another widget, this widget becomes a child window inside parent. The new widget is deleted when its parent is deleted.
Moreover, anytime a object constructor ask you for a parent QWidget or QObject, you can think that Qt will delete the object when the parent is deleted.
I am a newbey as well, but I hope this help you.

Populating a QComboBox and a QTable[View|Widget] from javascript

I'm trying to write a script for an application developed with Qt, using javascript for the business logic and a .ui file for the GUI, but I'm facing two problems.
In the ui I declared a QComboBox, to which I successfully connect javascript functions to handle
signals such as editTextChanged, etc. I was wondering I cannot populate the combobox from within
javascript code, because the addItem function is not exposed to script-side code.
combobox.editTextChanged[action](ComboBoxChanged); // OK (action is "connect" or "disconnect")
combobox.addItem("element 1"); // Error!
Is there any (other) way to do this?
I need to show a set of items (strings) in a table-like component. I tried using a QTableView and
QTableWidget but I cannot insert or get items. For example, from javascript I cannot access the
setModel function of a QTableView (if at least I could create a QAbstractItemModel from
script...), neither I can access the item(row,col) function of a QTableWidget class, to set an
item's text. Is there any way to show a table of strings to the user, let edit them and retrieve
the modified contents?
Thanks in advance.
Antonio
Because the addItem() function isn't a slot, you'll need an intermediate public slot to handle the transaction. It'll be the same with the other functions you are trying to get at as well.

Resources