Connecting to signals of private widgets - qt

Witht QtCreator set up as default when you create a widget the class for it creates the form as private to the class. So you have for example something like this:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
//...
private:
Ui::MainWindow *ui;
};
Now what I want to know is how you connect to the signals within the ui. For example if this widget was embedded into a QStackedWidget and when a button is pressed the page displayed needs to change. I would have considered connecting to the button but ui is private so I cannot.
Do I have to create signals in MainWindow and then within that connect the 'ui' signals to them and thus bubble up the hierarchy? Or have I missed something simple?

You can't have an unrelated object connect to signals/slots of aggregate components, even if you could it would break encapsulation and become a maintenance nightmare.
You need to expose the signals/slots of the aggregate components by adding them to the MainWindow API, and then call the relative ui component method in the definition.
For example, in the MainWindow definition, add:
signals:
void buttonClicked();
And then in constructor, do:
connect( ui->button, SIGNAL( clicked() ), this, SIGNAL( buttonClicked() ) );
This way, your MainWindow class propagates signals from it's aggregates - but finetuned to exactly how you intend the class to be used.

Related

Qt: No defined slots show up in Signal & Slot Editing

I have declared three slots in my mainwindow.h and given their definitions in the implementation file. Here is the MainWindow class:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void nextImage(int direction);
private slots:
void updateImage(void);
void cameraControl(void);
void cameraStart(void);
private:
Ui::MainWindow *ui;
CMUCamera *camera;
ImageProcessing *process;
RenderImage *renderImage;
bool saveImgFlg;
QString path;
};
Going to mainwindow.ui, I have designed a menu bar for the user interface. There are three QActions, as shown in the figure below:
Then, I do the signal and slot editing. But the defined slots (udpateImage, cameraStart and cameraControl) in the header file do not appear in the slot list, as shown in the figure below:
Are there any other steps I missed here or is there something I did wrong? It is also noted QMainWindow, in the framework of which these slots should show up, I guess, is also not displayed in the list.
I know why that happens. For adding those custom slots, in addition to defining them in header and implementation files, they also should be added in priori by right clicking the QMainWindow, going to change signals and slots and manually adding them in the slot panel. This way is simpler than to code signal&slots.
A similar question has been reported here: my slots don't appear in the signal slot editor

Subclassing QUiloader and reimplementing createWidget function of it

I needed to read widget classnames, names etc from gui loaded via QUiloader.
And I got answer here that I needed to subclass QUiloader and reimplement its method.
I have MainWindow, and via menu/toolbar I load the file, and show it. And when I load I want to know what elements are in that gui to work further with them.
The code I got from a user here:
class UiLoader : public QUiLoader
{
Q_OBJECT
public:
QStringList *wlist;
UiLoader(QObject *parent = 0) : QUiLoader(parent) {}
virtual QWidget* createWidget(const QString &className, QWidget *parent =0, const QString &name = QString())
{
QWidget* widget = QUiLoader::createWidget(className, parent, name);
//here do my stuff with className, parent, name
return widget;
}
};
I used Uiloader to load my file. And it is working.
My question now is how I intercept createWidget before returning widget, I want to get the list of widget and then return Widgets.
I do not know how what is the efficient way to create a list as simple as this one:
0=>TextBox, 1=>Button, ...
I really do not care about the structure I just need to know which one comes first and what it is.
Thanks.
I wouldn't reimplement class loader at all honestly.. May be only if you need to 'inject' something into existing code which use QUiLoader a lot.. but in general only thing you need:
pWidget = ...->createWidget(...);
QList<QWidget *> widgets = pWidget->findChildren<QWidget *>();
here you go, your widgets contains list of all form components..

Tabbed Dialog Box using Qt Designer

I'm new to Qt and having a problem with the TabbedDialog box designed using the Qt Designer.
I have a Dialog dlg on which i have placed a tabWidget MyTabWidget containing two tabs Tab1 and Tab2. I want to make separate cpp files for each tab and define the functions in their respective files. the problem i'm having is how to access the UI widgets of the dialog dlg in these respective files.
There are a few steps to be taken here which is well-explained in the following documentation.
1) Include #include "ui_foo.h"
This is necessary to access the UI elements in your code. This is the file that is available through the QtDesigner and ui compiler, aka. uic process.
2) Either inherit Ui::Foo or have an object with composition with it within your class. It would be something like:
class Foo : public QWidget
{
Q_OBJECT
public:
Foo(QWidget *parent = 0);
private:
Ui::Foo ui;
};
or
class Foo : public QWidget, private Ui::Foo
{
Q_OBJECT
public:
Foo(QWidget *parent = 0);
};
3) Then you can use this instance to access the widgets (something like ui->foo) created by the QtDesigner application.
bool Foo::doStuff()
{
ui->foo()->doStuff();
}
You probably do not wish to have two separate source files and classes as you wrote, but if you wish, the above steps could be applied for both.
That being said, I think it is better if you go through the aforementioned documentation because it is lot more detailed about the several approaches, and how to access the UI components in your source code generated by QtDesigner.
You can pass a tab pointer to your function you want to use. Something like:
void Class1::yourFunction1(QWidget *tab1);
void Class2::yourFunction2(QWidget *tab2);
You can access these widget tabs like:
ui->tab
if it was created in QtDesigner.

error QPushButton in a dock widget is inaccessible

Newbie here, I put a dock widget in a main window, and there is a button in this dock widget panel, now I want to connect, this button with a function defined in the main window, it threw out an error, what should I do? Thanks
connect
(
perfectPanel_->btn_AAA,
SIGNAL(clicked()),
this,
SLOT(on_actionAAA_triggered()),
Qt::UniqueConnection
);
Error message is
$PWD/ui_perfectPanel.h: In constructor ‘xixi::xixi()’:
$PWD/ui_perfectPanel.h:71:18: error: ‘QPushButton* Ui_perfectPanel::btn_AAA’ is inaccessible
$PWD/xixi/xixi.cpp:51:25: error: within this context
Note that I have already managed to connect this with a toolbar button in the main window (xixi.cpp), it works great.
This happens because your dock class, perfectPanel, inherits privately from the generated ui class Ui::perfectPanel:
class perfectPanel : public QWidget, private Ui::perfectPanel
You could make that inheritance public, but shouldn't. Instead you should make the signal part of the perfectPanel class, and route the internal signal from the button to that external signal:
class perfectPanel ... {
...
signals:
void AAA_clicked();
};
perfectPanel::perfectPanel() {
setupUi(this);
connect(btn_AAA, SIGNAL(clicked()), this, SIGNAL(AAA_clicked()));
}
(And in case you would ask, yes, you can connect 2 signals together).
Then you simply connect the new signal inside your main window class:
connect(perfectPanel_,
SIGNAL(AAA_clicked()),
this,
SLOT(on_actionAAA_triggered()),
Qt::UniqueConnection
);

QT NOOB: Add action handler for multiple objects of same type

I have a simple QT application with 10 radio buttons with names radio_1 through radio_10. It is a ui called Selector, and is part of a class called TimeSelector
In my header file for this design, i have this:
//! [1]
class TimeSelector : public QWidget
{
Q_OBJECT
public:
TimeSelector(QWidget *parent = 0);
private slots:
//void on_inputSpinBox1_valueChanged(int value);
//void on_inputSpinBox2_valueChanged(int value);
private:
Ui::Selector ui;
};
//! [1]
the commented out void_on_inputSpinBox1_valueChanged(int value) is from the tutorial for the simple calculator. I know i can do:
void on_radio_1_valueChanged(int value);
but I would need 10 functions. I want to be able to make one function that works for everything, and lets me pass in maybe a name of the radio button that called it, or a reference to the radio button so i can work with it and determine who it was.
I am very new to QT but this seems like it should be very basic and doable, thanks.
You can create a unique slot and obtain the object that emitted the signal with the QObject::sender() method. The following code presents an example of such slot:
public slots:
void onRadioToggled(bool checked)
{
QRadioButton *radio = qobject_cast< QRadioButton* >(QObject::sender());
// radio is the object that emitted the triggered signal
// if the slot hasn't been triggered by a QRadioButton, radio would be NULL
if (radio) {
qDebug() << radio->objectName() << " is set to " << checked << ".";
}
}
Note that radio->objectName() will not give you a good result unless you define it explicitly somewhere.
Now, you can connect the toggled(bool checked) signal of every QRadioButton to the onRadioToggled slot. Note that QRadioButton does not have any valueChanged signal so your code cannot actually work.
connect(radio_1, SIGNAL(toggled(bool)), SLOT(onRadioToggled(bool)));
connect(radio_2, SIGNAL(toggled(bool)), SLOT(onRadioToggled(bool)));
...
connect(radio_10, SIGNAL(toggled(bool)), SLOT(onRadioToggled(bool)));
In the radiobutton case, add the buttons to a QButtonGroup.
Similar functionality offers QSignalMapper.
What you can do is to create your own radio button class that inherits from QRadioButton and create a signal. This signal can have all the parameters you want.
void CheckWithReference(YourRadioButtonClass* rb);
or
void CheckWithReference(QString RadioButtonName);
or anything you would like to have.
Then create a slot in your TimeSelector class with the same set of parameters you will connect to all signals.

Resources