How to add 2 custom buttons for QLineEdit? - qt

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?

Related

EventFilter capturing events from Different Objects on Mac and Windows

I am working on an application for Windows and Mac. I am noticing different behavior for Mac and Windows.
When I set a QLIstView for a QComboBox and try to capture the Enter/Return press events from the PopUp of the comboBox, the eventFilter gets the event from the QListView on Windows and QComboBox on Mac,
Thus, the same code results in different output because of this.
Here's the code:
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QEvent>
#include<QComboBox>
#include<QListView>
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
bool eventFilter( QObject * inObject, QEvent * inEvent );
private:
Ui::MainWindow *ui;
QComboBox * mComboBox;
QListView * mListView;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QStandardItemModel>
#include<QStandardItem>
#include<QList>
#include<QDebug>
#include<QKeyEvent>
#include<QHBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui( new Ui::MainWindow ),
mComboBox( new QComboBox() ),
mListView( new QListView( mComboBox ) )
{
ui->setupUi(this);
mComboBox->setFixedSize( 200, 25 );
mListView->setFixedWidth( 200 );
QWidget * centralWidget = new QWidget( this );
QHBoxLayout * layout = new QHBoxLayout( centralWidget );
QStandardItem * font1 = new QStandardItem( "Item1" );
QStandardItem * font2 = new QStandardItem( "Item2" );
QStandardItem * font3 = new QStandardItem( "Item3" );
QStandardItem * font4 = new QStandardItem( "Item4" );
QStandardItem * font5 = new QStandardItem( "Item5" );
QStandardItemModel * model = new QStandardItemModel( mListView);
model->insertRow( 0, font1 );
model->insertRow( 1, font2 );
model->insertRow( 2, font3 );
model->insertRow( 3, font4 );
model->insertRow( 4, font5 );
mListView->setStyleSheet( "background-color: yellow" );
mComboBox->setModel( model );
mComboBox->setView( mListView );
layout->addWidget( mComboBox );
centralWidget->setLayout( layout );
setCentralWidget( centralWidget );
mListView->installEventFilter( this );
mComboBox->installEventFilter( this );
}
bool
MainWindow::eventFilter( QObject * inObject, QEvent * inEvent )
{
if( inObject == mListView )
{
if( inEvent->type() == QEvent::KeyPress )
{
QKeyEvent * keyEvent = static_cast< QKeyEvent * >( inEvent );
if( keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return )
{
qDebug() << " From mListView";
}
}
}
else if( inObject == mComboBox )
{
if( inEvent->type() == QEvent::KeyPress )
{
QKeyEvent * keyEvent = static_cast< QKeyEvent * >( inEvent );
if( keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return )
{
qDebug() << " From mComboBox";
}
}
}
return QObject::eventFilter( inObject, inEvent );
}
MainWindow::~MainWindow()
{
delete ui;
}
see the images below for output from Mac and Windows

How to make latency of QPushButton for push?

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 );
}

Qt ItemDelegate with a tool button: can't click

I use a custom widget for an item delegate.
This widget is composed of a combobox and a tool button, see below for the source.
Now when I use this widget in an item delegate, pressing on the tool button has no effect if the combobox has not the focus.
For a demo, see this video: http://youtu.be/o5AgjC4cCqY
Any idea how to handle this?
Thanks a lot!
Source of the widget:
QgsFieldExpressionWidget::QgsFieldExpressionWidget( QWidget *parent )
: QWidget( parent )
{
QHBoxLayout* layout = new QHBoxLayout( this );
layout->setContentsMargins( 0, 0, 0, 0 );
mCombo = new QComboBox( this );
mCombo->setEditable( true );
mCombo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
mButton = new QToolButton( this );
mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
mButton->setIcon( QgsApplication::getThemeIcon( "/mIconExpressionEditorOpen.svg" ) );
layout->addWidget( mCombo );
layout->addWidget( mButton );
}
Source of the delegate:
QgsComposerColumnSourceDelegate::QgsComposerColumnSourceDelegate( QgsVectorLayer* vlayer, QObject* parent ) : QItemDelegate( parent ),
mVectorLayer( vlayer )
{
}
QWidget* QgsComposerColumnSourceDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
Q_UNUSED( option );
Q_UNUSED( index );
QgsFieldExpressionWidget *fieldExpression = new QgsFieldExpressionWidget( parent );
fieldExpression->setLayer( mVectorLayer );
connect( fieldExpression, SIGNAL( fieldChanged( QString ) ), this, SLOT( commitAndCloseEditor() ) );
return fieldExpression;
}
void QgsComposerColumnSourceDelegate::setEditorData( QWidget* editor, const QModelIndex& index ) const
{
QString field = index.model()->data( index, Qt::EditRole ).toString();
//set the value for the field combobox
QgsFieldExpressionWidget *fieldExpression = static_cast<QgsFieldExpressionWidget*>( editor );
fieldExpression->setField( field );
}
void QgsComposerColumnSourceDelegate::setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const
{
QgsFieldExpressionWidget *fieldExpression = static_cast<QgsFieldExpressionWidget*>( editor );
QString field = fieldExpression->currentField();
model->setData( index, field, Qt::EditRole );
}
void QgsComposerColumnSourceDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
Q_UNUSED( index );
editor->setGeometry( option.rect );
}
Add the following line to your QgsFieldExpressionWidget constructor anywhere after the QComboBox is created:
setFocusProxy(mCombo);

Connecting QWidget to slot QStackedWidget::setCurrentWidget

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.

QPainter and QTimer

How to use QPainter and QTimer to draw a real time sinusoid like
sinus( 2 * w * t + phi )
thanks.
I would assume something like this, for the interaction between QTimer and painting:
// Periodically paints a sinusoid on itself.
class SinPainter : public QWidget
{
Q_OBJECT
public:
SinPainter( QWidget *parent_p = NULL ) :
QWidget( parent_p ),
m_timer_p( new QTimer( this ) ),
m_t( 0.0 )
{
// When the timer goes off, run our function to change the t value.
connect( m_timer_p, SIGNAL( timeout() ), SLOT( ChangeT() ) );
// Start the timer to go off every TIMER_INTERVAL milliseconds
m_timer_p->start( TIMER_INTERVAL );
}
// ...
protected slots:
void ChangeT()
{
// Change m_t to the new value.
m_t += T_INCREMENT;
// Calling update schedules a repaint event, assuming one hasn't
// already been scheduled.
update();
}
protected:
void paintEvent( QPaintEvent *e_p )
{
QPainter painter( this );
// Use painter and m_t to draw your current sinusoid according
// to your function.
}
private:
QTimer *m_timer_p;
double m_t; // <-- Or whatever variable type it needs to be.
};

Resources