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.
Related
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.
I want to run a function of a class as a thread continuously,till the object of the class is destroyed.
client.h
class client:public QWidget
{
Q_OBJECT
public:
//some declarations
client();
void setclientui();
//some ui elements
void receiveme(); //i want this function to be run as a thread
//It has to be run continuously to receive
//messages from socket and when a message is
//received ,it must display it in the gui.
public slots:
int prework();
void sendme();
};
Note:receiveme() uses recv() of tcp sockets which gets blocked until message is received.
client.cpp
void receiveme(){
while(1){
if(recv(sockfd,receivebuf,1024,0)<0)
{
qDebug()<<errno;
break;
}
receivebuf[20]='\0';
qDebug()<<receivebuf;
outputbox->append(a);
}}
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
Dialog* newdialog;//join a new chat
QString ipp,portt;
QTabWidget *wdg;
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void receivesocketaddress();
void on_actionJoin_a_chat_triggered();
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
wdg=new QTabWidget;
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionJoin_a_chat_triggered()
{
newdialog=new Dialog();
newdialog->setWindowTitle("Join a chat");
newdialog->setModal(true);
qDebug()<< QObject::connect(newdialog->conne,SIGNAL(clicked()),this,SLOT(receivesocketaddress()));
newdialog->exec();
}
void MainWindow::receivesocketaddress()
{
client *aclient=new client;
aclient->iptoconnect=newdialog->ip->text().toLocal8Bit().data();
aclient->porti=newdialog->port->text().toLocal8Bit().data();
if(aclient->prework()==0)//ie connected
{
newdialog->close();
wdg->addTab(aclient,tr("new chat"));
setCentralWidget(wdg);
//here the ui is shown.Now the aclient->receiveme() should
//running
}
else
{
newdialog->displayerror();
layout->addWidget(error,3,0,2,2);
qDebug()<<"cud not connect";
}
}
If aclient->prework()==0 then a gui is displayed but how can i run aclient->receiveme() at this time as a thread so that it is continuously running and reading messages from socket.If a message is received,it should be displayed in the gui.
Without thread the gui would freeze.I tried to use QThread::movetothread() but i receive the following error
QThread::cannot move object with parent
and to use subclass method, client class must inherit QThread but since it is already inheriting QWidget,the following error is thrown
call to QObject is ambiguous
How can i use QThread here?
Widgets can run only within GUI thread, so you need to implement client as QObject subclass and communicate with UI via signal/slot connection. Qt wont allow you to do outputbox->append(a) in non UI thread (Supposing that outputbox is some QWidget here);
You probably don't even need to use threads here - Qt provides it's own socket classes with event (signal/slot) based API;
If you still need to use recv() in different thread, you need to subclass QThread (one approach) or QObject (another approach); In both cases you need to have signal like messageReceived(QByteArray) that will be connected to slot in your UI object that will handle message; So receiveme() slot might looks like:
void client::receiveme()
{
while(1){
if(recv(sockfd,receivebuf,1024,0)<0)
{
qDebug()<<errno;
break;
}
receivebuf[20]='\0';
QByteArray msg(receivebuf);
emit messageReceived(msg);
}
}
This article might help
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'm trying to change text of a class Label from another class. I have class MainWindow, which contains Label.
I also have a Bot class from which I wanna change the value of label.
I'm trying to create signal and slots but I have no idea where to start.
I created signal and slots like so:
//in mainwindow.h
signals:
void changeTextSignal();
private slots:
void changeText();
//in mainwindow.cpp
void MainWindow::changeText(){
this->label->setText("FooBar");
}
But I have no idea how to connect a signal to be able to change Label's text from another class.
Read up on Qt signal-slot mechanism. If I understand you correctly, you are trying to signal from Bot to MainWindow that the Label text needs to change. Here's how you do it...
//bot.h
class Bot
{
Q_OBJECT;
//other stuff here
signals:
void textChanged(QString);
public:
void someFunctionThatChangesText(const QString& newtext)
{
emit textChanged(newtext);
}
}
//mainwindow.cpp
MainWindow::MainWindow
{
//do other stuff
this->label = new QLabel("Original Text");
mybot = new Bot; //mybot is a Bot* member of MainWindow in this example
connect(mybot, SIGNAL(textChanged(QString)), this->label, SLOT(setText(QString)));
}
void MainWindow::hello()
{
mybot->someFunctionThatChangesText("Hello World!");
}
So basically i have a little application that loads two plugins and connect them. First plugin after it's loaded it creates a label without any title which will be added to main window. Second plugin creates an action which will be added to a menu. So my app need just to load these plugins and to connect them . What i mean by connecting them ? i mean that label plugin contains a slot which will modify label's title , and action plugin has a signal declared. Application should connect action plugin signal with label slot. I do not know how to do it exactly. My guess is that in action plugin class implementation is to connect custom signal with a standart signal (triggered). But anyway this ways my app is not working as i expected. How can i make a correct connection in my app for a signal from one plugin and slot from another plugin ??
Here is my code for Label Plugin :
#include "LabelInterface.h"
class LabelPlugin : public LabelInterface {
Q_OBJECT
Q_INTERFACES(LabelInterface)
public:
QLabel* label;
QLabel* newLabel();
LabelPlugin() {}
~LabelPlugin() {}
public slots:
void setTextforLabel();
};
#include <QtGui>
#include "LabelPlugin.h"
QLabel* LabelPlugin::newLabel() {
label = new QLabel("");
return label;
}
void LabelPlugin::setTextforLabel() {
label->setText("This plugin works fine");
}
// Exporta plugin-ul
Q_EXPORT_PLUGIN2 (labelplugin,LabelPlugin)
Action Plugin :
#include "ActionInterface.h"
class ActionPlugin : public ActionInterface {
Q_OBJECT
Q_INTERFACES (ActionInterface)
public :
QAction* myAction;
QAction* newAction();
~ActionPlugin () {}
ActionPlugin () {}
public slots:
void send_signal();
signals :
void pushMyAction();
};
#include <QtGui>
#include "ActionPlugin.h"
QAction* ActionPlugin::newAction() {
myAction = new QAction("Show text",this);
return myAction;
}
void ActionPlugin::send_signal() {
qDebug ()<<"Here";
QAction::connect (this,SIGNAL(pushMyAction()),this,SIGNAL(triggered()));
}
Q_EXPORT_PLUGIN2 (actionplugin,ActionPlugin)
In my app , where i try to load plugins i have :
foreach (QString fileName, appDir.entryList(QDir::Files)) {
qDebug()<<QString(fileName);
QPluginLoader pluginLoader(appDir.absoluteFilePath(fileName));
QObject* plugin = pluginLoader.instance();
if (plugin) {
ActionInterface* myAction= qobject_cast<ActionInterface*>(plugin);
if (myAction) {
action_ = myAction;
pluginMenu->addAction(action_->newAction());
}
LabelInterface* myLabel = qobject_cast<LabelInterface*>(plugin);
if (myLabel) {
label_=myLabel;
layout->addWidget(label_->newLabel());
}
if (action_ && label_) {
qDebug()<<"both loaded";
action_->send_signal();
connect(action_, SIGNAL(pushMyAction()),label_, SLOT(setTextforLabel()));
}
else qDebug() << "seems one plugin is not loaded";
}
}
You need to be able to access a QObject instance from each plugin so you can use it in the connect call. I would add methods to your interfaces to do this. One pattern I've seen is an operator to convert the interface to a QObject pointer, like:
class MyInterface {
public:
virtual operator QObject*() = 0;
};
Opinions may vary on whether that's good style, but it solves the problem (if you don't like the operator, use a method called asQObject() or similar).