I'm attempting to toggle stacked push buttons as show in the following application.
Declaration:
#include <QPushButton>
#include <QMainWindow>
#include <QStackedWidget>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
QPushButton* m_button[2];
QStackedWidget *m_buttonStack;
};
Implementation (take note of the connects):
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
resize(300, 300);
m_buttonStack = new QStackedWidget( this );
m_buttonStack->setGeometry( 100, 100 , 100 , 100 );
m_button[0] = new QPushButton( this );
m_button[0]->setText( "Button 1" );
m_buttonStack->addWidget( m_button[0] );
m_button[1] = new QPushButton( this );
m_button[1]->setText( "Button 2" );
m_buttonStack->addWidget( m_button[1] );
m_buttonStack->setCurrentWidget( m_button[1] );
QObject::connect( m_button[0] , SIGNAL( clicked() ) , m_buttonStack , SLOT( setCurrentWidget( m_button[1] ) ) );
QObject::connect( m_button[1] , SIGNAL( clicked() ) , m_buttonStack , SLOT( setCurrentWidget( m_button[0] ) ) );
}
For some inexplicable reason, although QStackedWidget::setCurrentWidget is defined QObject::connect is unable to connect to it, as the following error messages, copied from the application output window, show:
Object::connect: No such slot QStackedWidget::setCurrentWidget( m_button[1] ) in ..\mainwindow.cpp:21
Object::connect: No such slot QStackedWidget::setCurrentWidget( m_button[0] ) in ..\mainwindow.cpp:22
you'll want to use a QSignalMapper
connect(m_button[0], SIGNAL(clicked()), m_signalMapper, SLOT(map()));
m_signalMapper->setMapping(m_button[0],m_button[1]);
connect(m_button[1], SIGNAL(clicked()), m_signalMapper, SLOT(map()));
m_signalMapper->setMapping(m_button[1],m_button[0]);
QObject::connect(signalMapper , SIGNAL( mapped(QWidget *) ) , m_buttonStack , SLOT( setCurrentWidget(QWidget *) ) );
You don't need to provide the actual argument(s) when refer to the function signature in the SLOT macro:
QObject::connect( m_button[0], SIGNAL( clicked() ), m_buttonStack, SLOT( setCurrentWidget( m_button[1] ) ) );
Should be something like this:
QObject::connect( m_button[0], SIGNAL( clicked() ), m_buttonStack, SLOT( setCurrentWidget( QWidget *) ) );
As you could see, even in this way, the connection will not work. I suggest to implement your own slot (without arguments) and connect your buttons clicks to it:
QObject::connect(m_button[0], SIGNAL(clicked()), this, SLOT(onButtonClicked()));
than, in the slot, you can handle the click:
void MainWindow::onButtonClicked()
{
// Get the button clicked
QPushButton *btn = qobject_cast<QPushButton *>(sender());
m_buttonStack->setCurrentWidget(btn);
}
Thus you can even remove your buttons array.
Related
I tried to add two buttons for my line edit. The "clear" appears only when the text in line edit not empty, and the "bulb" is always shown.
MyLineEdit.cpp
MyLineEdit::MyLineEdit( QWidget *p_parent ) : QLineEdit( p_parent )
{
m_buttonAction = addAction( QIcon( ":/bulb" ), QLineEdit::TrailingPosition );
QToolButton *button = dynamic_cast<QToolButton *>( m_buttonAction->associatedWidgets().at( 1 ) );
button->setCursor( QCursor( Qt::PointingHandCursor ) );
m_buttonAction->setVisible( true );
m_clearAction = addAction( QIcon( ":/clear" ), QLineEdit::TrailingPosition );
QToolButton *clear = dynamic_cast<QToolButton *>( m_clearAction->associatedWidgets().at( 1 ) );
clear->setCursor( QCursor( Qt::PointingHandCursor ) );
m_clearAction->setVisible( false );
connect( this, &MyLineEdit::textChanged, this, &MyLineEdit::toggleClearButton );
connect( m_clearAction, &QAction::triggered, this, &QLineEdit::clear );
connect(m_buttonAction, &QAction::triggered, this, &MyLineEdit::doSomething);
}
void MyLineEdit::toggleClearButton()
{
text().isEmpty() ? m_clearAction->setVisible( false ) : m_clearAction->setVisible( true );
}
void MyLineEdit::doSomething()
{
}
MyLineEdit.h
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit( QWidget *p_parent = nullptr );
private slots:
void toggleClearButton();
void doSomething();
private:
QAction *m_clearAction = nullptr;
QAction *m_buttonAction = nullptr;
};
When I run the program, the "bulb" does not appear at the beginning
Only when I type something in the line edit, the "bulb" is then shown as I want
Why is the "bulb" not shown at the beginning, where do I have error here?
I would like to create QPushButton which gives an opportunity to press not often than one time in 200 msec. When I use func sleep(200) all GUI thread will stop.
Waiting for your ideas!
Thankx!
Something like this:
class Controller : public QObject
{
// ...
private:
QPointer< QPushButton > btn;
private slots:
void onClicked();
void enableClick();
};
Controller::onClicked()
{
disconnect( btn, SIGNAL( clicked() ), SLOT( onClicked() ) );
QTimer::singleShot( 200, this, SLOT( enableClick() ) );
// Optional
btn->setEnabled( false );
}
Controller::enableClick()
{
connect( btn, SIGNAL( clicked() ), SLOT( onClicked() ) );
// Optional
btn->setEnabled( true );
}
i Guys ,
Qt Version 5.1
I am working on existing qt project and I failed to understand why when I click on button , it fails to fire up function in slot
What I am trying to do is my Qt application connects to the network and displays all the machine with their mac address using QTreewidget. This part works fine
my nest task is to select the mac-adrress from the QTree object created in above step AND then create a pushbutton to start the upgrade process on that machine.
Below is my source code
1) main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Regular_Work w;
w.show();
return a.exec();
}
2) regular_work.cpp
Regular_Work::Regular_Work(QWidget *parent)
: QMainWindow(parent),macAdd_tree_p_( 0 ), reg_upgrade_button_(0),
box_table_p_( 0 ),
udp_listner_p_( 0 )
{
ui.setupUi(this);
// Create the main view
create_main_view( this, macAdd_tree_p_, box_table_p_ , reg_upgrade_button_);
init(); // this function upgradels other signals and slots from other class to find the network and upgradel the slots which displays teh tree view of mac address connected to a network.
create_menu_actions();
}
Regular_Work::~Regular_Work()
{
}
// this function is called from another slot when itemClicked signal is received from QTreeWidgetItem
void Regular_Work::set_reg_upgrade_button_visible( Regular_Work* main_p )
{
QPushButton* reg_upgrade_button = new QPushButton ("Regular_upgradei");
reg_upgrade_button->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ;
QWidget* centralWidget = new QWidget( main_p );
centralWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
QHBoxLayout* layout = new QHBoxLayout(centralWidget);
layout->addWidget( reg_upgrade_button_ );
main_p->setCentralWidget(centralWidget);
reg_upgrade_button->setVisible( true );
connect(reg_upgrade_button, SIGNAL( clicked() ), main_p, SLOT( start_Work( "start Work" ) ) ); // this is teh problem ?
}
void Regular_Calibration::start_Work( const QString& error_message )
{
QMessageBox::information( this,
tr( "Push button works " ),
error_message );
}
Thanks a lot for the help
Your problem lies in the fact that you're trying to pass a parameter value in the connect statement. This can not work: -
SLOT( start_Work( "start Work" ) )
What you need to do is to create a slot that matches the arguments of the clicked() signal. Then in that slot function, you can call your start_Work("start Work") function. Something like this: -
class Regular_Work : public QMainWindow
{
Q_OBJECT
private:
void start_Work(const QString&);
private slots:
void ReceiveButtonClicked();
};
void RegularWork::ReceivedButtonClicked()
{
start_Work("start Work");
}
Connect the signal and slots: -
connect(reg_upgrade_button, SIGNAL( clicked() ), main_p, SLOT( ReceiveButtonClicked()));
If you use Qt 5, you can use the new connection syntax: -
connect(reg_upgrade_button, &QPushButton::clicked, main_p, &RegularWork::ReceiveButtonClicked);
This has the advantage of telling you if there's a problem at compile time, as well as taking pointers to functions, so you don't specify any arguments for the functions.
I've got some problem with signal for a button in Qt 4.8.0. I am using vs 2010 with Qt Designer. I have created a button in Designer with playButton name. But after that I tried to connect clicked() signal (in vs) with my function from CRenderArea (to start a timer), but it seems that it doesn't work (the function start() works when I put it in the constructor, so it's not the problem of the code itself). The code is compiling, the program is executing, but after clicking a button - nothing happens (it should move a line).
I would be really thankful for some help, just started a fun with Qt.
The codes are here (I hope the number of files won't scare you, these are the simplest codes ever :) ):
main.cpp
#include "ts_simulator.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TS_simulator w;
w.show();
return a.exec();
}
ts_simulator.cpp:
TS_simulator::TS_simulator(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
p_map = new CRenderArea();
ui.setupUi( this );
p_map->setParent( ui.renderArea );
// this doesn't work, why?
connect( ui.playButton, SIGNAL( clicked() ), this, SLOT( p_map->start() ) );
}
CRenderArea.h
#pragma once
#include <QtGui>
class CRenderArea : public QWidget {
Q_OBJECT // I think it's necessary?
int x;
QBasicTimer* timer;
public:
CRenderArea();
public slots: // this is necessary too, right?
void start();
private:
void timerEvent( QTimerEvent* );
void paintEvent( QPaintEvent* );
};
and CRenderArea.cpp:
#include "CRenderArea.h"
CRenderArea::CRenderArea() : x( 0 ) {
setBackgroundRole( QPalette::Base );
setMinimumSize( 591, 561 );
setAutoFillBackground( true );
timer = new QBasicTimer();
}
void CRenderArea::timerEvent( QTimerEvent* e ) {
++x;
update();
}
void CRenderArea::paintEvent( QPaintEvent* p ) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::darkGray);
painter.drawLine(2+x/10, 8, 60, 300);
}
void CRenderArea::start() {
timer->start( 0, this );
}
Greets.
The problem is here:
connect( ui.playButton, SIGNAL( clicked() ), this, SLOT( p_map->start() ) );
if p_map is the receiver of the signal, and it has Q_OBJECT, it should be written as:
connect( ui.playButton, SIGNAL( clicked() ), p_map, SLOT(start()) );
I think I have some fundamental misunderstanding of how the Qt signal/slot mechanism works.
I have worked through example programs and they make sense but when I've tried to take those and modify them I have been getting results I do not understand. I have attach a code sample below that is a boiled-down version of what I was trying to do that certainly does not do what I want it to. Am I misusing the signal/slot mechanism and or the QString class? Is the way I am using the signal/slot to modify things in a coupled fashion creating an infinite loop? Any help greatly appreciated.
// test.cpp
#include <QApplication>
#include <QDialog>
#include <QLineEdit>
#include <QString>
#include <QVBoxLayout>
class myDialog : public QDialog
{
Q_OBJECT
public:
myDialog() : a_( new QLineEdit ), b_( new QLineEdit )
{
QVBoxLayout* layout( new QVBoxLayout( this ) );
layout->addWidget( a_ );
layout->addWidget( b_ );
connect( a_, SIGNAL( textChanged( const QString& ) ),
this, SLOT( aChanged( const QString& ) ) );
connect( b_, SIGNAL( textChanged( const QString& ) ),
this, SLOT( bChanged( const QString& ) ) );
}
private:
QLineEdit* a_;
QLineEdit* b_;
private slots:
void aChanged( const QString& qs );
void bChanged( const QString& qs );
};
#include "test.moc"
void myDialog::aChanged( const QString& qs )
{
b_->setText( QString::number( 2.0 * qs.toDouble() ) );
}
void myDialog::bChanged( const QString& qs )
{
a_->setText( QString::number( 3.3 * qs.toDouble() ) );
}
int main( int argc, char** argv )
{
QApplication a( argc, argv );
myDialog d;
d.show();
return a.exec();
}
Because In aChanged, you edit the b QLineEdit, it triggers the textChanged() signal for b...causing it to call bChanged, changing a..... etc. etc.
I think that is your problem here.
You might want to use textEdited() in stead.
Not so critical in this case, but please pay attention to delete a_ and b_ in the destructor since they dont have any parent.