Consider this QWidget initialized as:
QWidget *Logger;
Logger = new QWidget();
QPushButton *btn;
btn= new QPushButton(Logger);
btn->setObjectName(QStringLiteral("pushButton"));
Logger->show();
It display the Logger with a button with text pushButton.
Now Later if i want to access pushButton, i do it like this:
QPushButton *pushButton = Logger->findChild<QPushButton *>("pushButton");
pushButton->setText("NEW BUTTON");
I want to know is there a possibility to access directly this pushButton from Logger??Something like:
Logger->btn ...
I tried but it does not work. I have Widgets defined like this with many child objects and i wonder is this the only way to access them at run time??
EDIT: #drescherjm, So something along these lines you mean:
class MyWidget : QWidget
{
public:
QPushButton *pushButton;
MyWidget(){
pushButton = new QPushButton(this);
}
};
MyWidget *w = new MyWidget();
w->pushButton->setText("XYZ");
And is it worth it to create so many classes?? for small redundant tasks?
It won't work the way that you are expecting it to work. Use btn as long as it is in scope.
If you are creating btn somewhere locally, but your use-case demands you to use it in different places across your code, then you need to reconsider your design and make the QPushButton part of a class member.
Something of this sort :
#include <QPushButton>
class SampleWidget : public QWidget
{
public :
SampleWidget( QWidget * inParent );
// public methods to change the properties of the QPushButton go here.
void SetButtonText( QString const & inString );
bool IsButtonChecked();
private :
QPushButton *mSampleButton;
};
And in the implementation :
SampleWidget::SampleWidget(QWidget *parent)
:
mSampleButton( new QPushButton( parent ) )
{
// connect( mSampleButton,......... ); Connection to slot
}
void SampleWidget::SetButtonText( QString const & inString )
{
mSampleButton->setText( inString );
}
bool
SampleWidget::IsButtonChecked()
{
return mSampleButton->isChecked();
}
The question was not very clear on what you exactly want, but it seems like you are struggling to understand how to alter the attributes of a push button if it is a private member of a class and the above example will help you with that.
Related
I'm trying to make a simple test to use an UI object made with "Qt Design" but I'm pretty new to Qt and C++.
I've got a quite simple Ui : 3 LineEdits and 1 PushButton :
IMAGE : the UI window
I've a Client Class which is supposed to control Ui. It connects the QPushButton and it should get the content from QLineEdit.
But the result in QDebug is always the same when I push the Button, even when I change QlineEdit field: "Client connected : "" : 0 "
Moreover, if I use on_pushButton_clicked made with QtDesign, it will display the real values of QlineEdits.
Why the QStrings are always the same ? Am I passing a copy of the initial object ? How to solve that ?
Is it the good way to make a ViewController ? Else, what is the good way?
Client.cpp
#include "client.h"
#include "mainwindow.h"
#include "logwindow.h"
Client::Client()
{
LogWindow* w1 = new LogWindow();
MainWindow* w2 = new MainWindow();
_stack = new QStackedWidget();
_stack->addWidget(w1);
connect(w1->getButton(),SIGNAL(clicked()),this,SLOT(connexion()));
_stack->addWidget(w2);
_stack->show();
}
//When the button is Pushed, gets the content from QlineEdits and prints them
void Client::connexion()
{
QString ip=(LogWindow (_stack->currentWidget())).getIP();
int port=((LogWindow (_stack->currentWidget())).getPort()).toInt();
socket = new QTcpSocket(this);
socket->connectToHost(ip, port);
_stack->setCurrentIndex((_stack->currentIndex()+1)%_stack->count());
qDebug() <<"Client connected : " << ip << ":"<<port;
}
And a class made automatically by Qt :
LogWindow.cpp
#include "logwindow.h"
#include "ui_logwindow.h"
LogWindow::LogWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::LogWindow)
{
ui->setupUi(this);
}
LogWindow::~LogWindow()
{
delete ui;
}
QPushButton* LogWindow::getButton()
{
return ui->pushButton;
}
QString LogWindow::getIP()
{
//LineEdit named "IP_text"
return ui->IP_text->text();
}
QString LogWindow::getPort()
{
//LineEdit named "Port_text"
return ui->Port_text->text();
}
LogWindow.h
namespace Ui {
class LogWindow;
}
class LogWindow : public QWidget
{
Q_OBJECT
public:
explicit LogWindow(QWidget *parent = 0);
~LogWindow();
QPushButton* getButton();
QString getIP();
QString getPort();
private slots:
void on_pushButton_clicked();
private:
Ui::LogWindow *ui;
};
Thuga solved it :
In Client::connexion you are creating a new instance of LogWindow.
Make LogWindow* w1 a member variable of your Client class, if you want
to access it in other Client's member functions as well.
There is not much to complain about, except that _stack is a widget
without a parent, so you must make sure you destroy it when you don't
need it anymore (for example call delete _stack; in the destructor).
Most beginners would have tried to make the ui variable public to get
the data from IP_text, but you did correctly, by making the
LogWindow::getIP function.
If you don't want to expose ui->pushButton outside of your class, you
can make a signal for your LogWindow class, and connect the clicked
signal of ui->pushButton to that signal. You can connect signals to
signals, it doesn't have to be a slot.
I'm trying to develop a file browser in Qt and C++.
Opening a FileSystem can take a lot of memory. In that way, the best is to only open what is inside a folder when I click on it.
In my browser.h, I have declared the OnClick signal.
class Browser : public QTreeWidget
{
Q_OBJECT
public:
Browser(USBDevice dev, QWidget* parent = 0);
QTreeWidget(parent)
{
connect(this , SIGNAL(itemClicked(QTreeWidgetItem*,int)),this,
// SLOT(showDirectory(QTreeWidgetItem*,int)));
};
~Browser(){};
public slots:
void showDirectory(QTreeWidgetItem* item, int /*column*/)
{
...
}
};
QTreeWidget is failing to build saying :
error: function definition does not declare parameters - QTreeWidget(parent)
in the browser.cpp, I have wrote the code to create window, widget..
Browser::Browser(USBDevice dev, QWidget *parent) :
QTreeWidget(parent)
{
QMainWindow *window = new QMainWindow();
window->setWindowTitle(QString::fromUtf8("PULS"));
window->resize(400, 400);
QWidget *centralWidget = new QWidget(window);
QTreeWidget *MyTree = new QTreeWidget(centralWidget);
MyTree->setFixedSize(395,395);
}
//Set QTreeWidget Column Header
QTreeWidgetItem* headerItem = new QTreeWidgetItem();
headerItem->setText(0,QString("File Name"));
headerItem->setText(1,QString("Size (Bytes)"));
headerItem->setText(2,QString("Date"));
MyTree->setHeaderItem(headerItem);
I don't understand but How to manage connect ?
You've got a ; instead of a : before the initialiser list for your constructor:
Browser(USBDevice dev, QWidget* parent = 0); // <--- here
QTreeWidget(parent)
{
...
FWIW, I recommend putting the colon at the start of the line like this:
Browser(USBDevice dev, QWidget* parent = 0)
: QTreeWidget(parent)
{
...
That way it's much clearer how the second line relates to the first and third, and you'll get in the habit of editing the declaration when you go to make it a definition, avoiding the kind of problem you had.
I have the code like this:
class MyListView : public QListView
{
public:
MyListView();
~MyListView();
public slots:
void insertData();
void deleteData();
void showData();
private:
QStringListModel *model;
QListView *listView;
};
And the constructor is like:
MyListView :: MyListView()
{
QStringList data;
data << "Letter A" << "Letter B" << "Letter C";
model = new QStringListModel;
model->setStringList(data);
listView = new QListView;
listView->setModel(model);
/* the three buttons */
QPushButton *insertBtn = new QPushButton(QObject::tr("insert"),this);
QObject::connect(insertBtn,SIGNAL(clicked()),this,SLOT(insertData()));
QPushButton *deleteBtn = new QPushButton(QObject::tr("delete"),this);
QObject::connect(deleteBtn,SIGNAL(clicked()),this,SLOT(deleteData()));
QPushButton *showBtn = new QPushButton(QObject::tr("show"),this);
QObject::connect(showBtn,SIGNAL(clicked()),this,SLOT(showData()));
/* layout */
QHBoxLayout *btnLayout = new QHBoxLayout;
btnLayout->addWidget(insertBtn);
btnLayout->addWidget(deleteBtn);
btnLayout->addWidget(showBtn);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(listView);
mainLayout->addLayout(btnLayout);
setLayout(mainLayout);
}
So I want to connect the push button to the slot functions, but when I compile it, I got the error message as:
QObject::connect: No such slot QListView::insertData()
I think the problem comes from the connect function, in which, "this" is not the right pointer, any help? Thanks in advance.
You need to add the Q_OBJECT macro in your MyListView
From Qt API docs:
Notice that the Q_OBJECT macro is mandatory for any object that
implements signals, slots or properties. You also need to run the Meta
Object Compiler on the source file. We strongly recommend the use of
this macro in all subclasses of QObject regardless of whether or not
they actually use signals, slots and properties, since failure to do
so may lead certain functions to exhibit strange behavior.
So, it should be:
class MyListView : public QListView
{
Q_OBJECT
public:
...
}
I create several QradioButton and connect to the same SLOT. In the slot, I want to know which QradioButton invoke the slot and do the related action. I found there is a way by using qobject_cast and QObject::sender(), but it seems not work. Here is the code:
header file:
class dialoginput : public QDialog
{
Q_OBJECT
public:
dialoginput(QWidget *parent = 0);
QRadioButton *radio1;
QRadioButton *radio2;
QRadioButton *radio3;
private slots:
void setText_2();
private:
QLabel *label_0_0;
QLabel *label_1;
};
main file:
dialoginput::dialoginput(QWidget *parent): QDialog(parent){
label_0_0 = new QLabel("label_1:");
label_1 = new QLabel;
QWidget *window = new QWidget;
QVBoxLayout *windowLayout = new QVBoxLayout;
QGroupBox *box = new QGroupBox("Display Type");
radio1 = new QRadioButton("3");
radio2 = new QRadioButton("5");
radio3 = new QRadioButton("9");
QVBoxLayout *radioLayout = new QVBoxLayout;
connect(radio1,SIGNAL(clicked()),this,SLOT(setText_2()));
connect(radio2,SIGNAL(clicked()),this,SLOT(setText_2()));
connect(radio3,SIGNAL(clicked()),this,SLOT(setText_2()));
radioLayout->addWidget(radio1);
radioLayout->addWidget(radio2);
radioLayout->addWidget(radio3);
box->setLayout(radioLayout);
windowLayout->addWidget(box);
windowLayout->addWidget(label_0_0);
windowLayout->addWidget(label_1);
window->setLayout(windowLayout);
window->show();
}
void dialoginput::setText_2(){
QObject *object = QObject::sender();
QRadioButton* pbtn = qobject_cast<QRadioButton*>(object);
QString name = pbtn->objectName();
label_1->setText(name);
if(!QString::compare(name, "3")){
}
else if(!QString::compare(name, "5")){
}
else if(!QString::compare(name, "9")){
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
dialoginput *input = new dialoginput();
return a.exec();
}
Even though using the sender() method solves your problem, i do not recommend using it. The problem is, signals and slots are designed to seperate the emitter and the receiver. A receiver does not need to know which objects, even what types of objects can trigger its slot. When you use sender(), you are relying on the fact that the receiver has knowledge of all of the objects that triggers its slot. What if this changes in the future?
You should take a look at QSignalMapper, it is designed specifically for this kind of needs. There are good examples about it in the docs.
You could create separate wrapper slots for each radio button, which then passes the information to the function you want to call. Something like this: -
class dialoginput : public QDialog
{
Q_OBJECT
public:
QRadioButton *radio1;
QRadioButton *radio2;
QRadioButton *radio3;
private slots:
void Radio1Selected() { setText_2(1); }
void Radio2Selected() { setText_2(2); }
void Radio3Selected() { setText_2(3); }
private:
void setText_2(int id);
};
Then connect each radio button: -
connect(radio1,SIGNAL(clicked()),this,SLOT(Radio1Selected()));
connect(radio2,SIGNAL(clicked()),this,SLOT(Radio2Selected()));
connect(radio3,SIGNAL(clicked()),this,SLOT(Radio3Selected()));
Now when setText_2 is called, the id will represent the selected radio button.
You are getting sender Object correctly on setText_2(), But you are not setting objectName property of radio1, radio2 and radio3. Please use "setObjectName( )" API.
write single argument custom signal for radiobuttons and then emit it .catch that argument in slot.check for corresponding radio button
You could also create a QButtonGroup and use lambda expression (c++11)
class dialoginput : public QDialog
{
Q_OBJECT
public:
private:
void setText_2(int id);
QRadioButton *radio1;
QRadioButton *radio2;
QRadioButton *radio3;
QButtonGroup _btnGroup;
};
After add the 3 QRadioButton to the QButtonGroup
_btnGroup.addButton(radio1, 1);
_btnGroup.addButton(radio2, 2);
_btnGroup.addButton(radio3, 3);
connect(&_btnGroup, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), [=](int id){
setText_2(id);});
Here's a simple code that creates a button and assigns a onclick handler:
auto btn = new QPushButton("CLICK ME");
connect(btn, SIGNAL(clicked()), this, SLOT(btn_Click()));
private slots:
void btn_Click() {
alert("clicked!");
}
It works as it should if called in the main window class. However when I try to do this in a child window, clicking the button does nothing. The child window is shown like this:
auto settingsWindow = new SettingsWindow();
settingsWindow->show();
I guess it's somehow connected with the receiver object which is now a different window. But how can I make it work?
In order to be able to declare signals/slots in your own class you should include Q_OBJECT directive in your class:
class SettingsWindow {
Q_OBJECT
...
};
You should add a MACRO in class SettingsWindow to enable singal receiving.
Add "Q_OBJECT" like the following.
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget();
....