I have a ComboBox and set it to be edited.
QComboBox *myCombo = new QComboBox(this);
myCombo->setEditable(true);
myCombo->setStyleSheet("QComboBox::down-arrow{image: url(:/bulb.png);}");
myCombo->setCursor( QCursor( Qt::PointingHandCursor ) );
So now when i click onto the editing field, nothing happen. But what I need is, when I click onto the bulb (which is the down-arrow), something (like a table or a dialog....) should be appeared. How can I recognize this click event in this case? I looked at the list of signals for combo box but could not find any signal for that.
By overwriting the mousePressEvent() method you must use hitTestComplexControl() method to know that QStyle::SubControl has been pressed by issuing a signal if it is QStyle::SC_ComboBoxArrow.
#include <QtWidgets>
class ComboBox: public QComboBox
{
Q_OBJECT
public:
using QComboBox::QComboBox;
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *event) override{
QComboBox::mousePressEvent(event);
QStyleOptionComboBox opt;
initStyleOption(&opt);
QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, event->pos(), this);
if(sc == QStyle::SC_ComboBoxArrow)
emit clicked();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ComboBox w;
w.setEditable(true);
w.setStyleSheet("QComboBox::down-arrow{image: url(:/bulb.png);}");
QObject::connect(&w, &ComboBox::clicked, [](){
qDebug()<<"clicked";
});
w.show();
return a.exec();
}
#include "main.moc"
Although showPopup() is a possible option this can be called directly without the down-arrow being pressed, for example by calling it directly: myCombo->showPopup() so it is not the correct option.
A possible solution is to subclass QComboBox and reimplement showPopup() virtual method:
.h:
#ifndef COMBOBOXDROPDOWN_H
#define COMBOBOXDROPDOWN_H
#include <QComboBox>
#include <QDebug>
class ComboBoxDropDown : public QComboBox
{
public:
ComboBoxDropDown(QWidget *parent = nullptr);
void showPopup() override;
};
#endif // COMBOBOXDROPDOWN_H
.cpp:
#include "comboboxdropdown.h"
ComboBoxDropDown::ComboBoxDropDown(QWidget *parent)
: QComboBox (parent)
{
}
void ComboBoxDropDown::showPopup()
{
//QComboBox::showPopup();
qDebug() << "Do something";
}
Related
I have the following problem with the QTableWidget or QTableWidgetItem:
I would like to analyze the text in the cell during its editing/typing,
for example as a reaction on KeyReleaseEvent.
However the QTableWidgetItem::text() property is changed only AFTER the
cell editing is finished (focus has left the cell).
How can I overcome such behavior? Of course, it is possible to analyze the
button keys in the KeyReleaseEvent, but with the text() property it would be much easier...
One possible solution is to establish a custom QLineEdit as editor through the delegate:
#include <QtWidgets>
class LineEdit: public QLineEdit{
public:
using QLineEdit::QLineEdit;
protected:
void keyReleaseEvent(QKeyEvent *event) {
QLineEdit::keyPressEvent(event);
qDebug() << text();
}
};
class StyledItemDelegate: public QStyledItemDelegate{
public:
using QStyledItemDelegate::QStyledItemDelegate;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const{
LineEdit *editor = new LineEdit(parent);
return editor;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTableWidget w(10, 10);
w.setItemDelegate(new StyledItemDelegate(&w));
w.show();
return a.exec();
}
I'm in need of a checkable QAction, that has besides the modes checked and unchecked the option of a partially check. This is basically already what QCheckBox provides, but unfortunately, QAction doesn't provide.
As a first attempt, I came up with the following approach by implementing a custom QWidgetAction.
TriState.h
#pragma once
#include <QWidgetAction>
#include <QCheckBox>
#include <QLabel>
#include <QFrame>
#include <QHBoxLayout>
class TriStateAction : public QWidgetAction {
Q_OBJECT
public:
TriStateAction(QWidget* parent=nullptr) : QWidgetAction(parent) {
mChkBox = new QCheckBox;
mChkBox->setTristate(true);
auto widget = new QFrame;
widget->setLayout(new QHBoxLayout);
widget->layout()->addWidget(mChkBox);
widget->layout()->addWidget(new QLabel("TriState"));
setDefaultWidget(widget);
connect(mChkBox, &QCheckBox::stateChanged, this, &QWidgetAction::changed);
}
void setCheckState(Qt::CheckState checkState) {
mChkBox->setCheckState(checkState);
}
Qt::CheckState checkState() const {
return mChkBox->checkState();
}
private:
QCheckBox* mChkBox{ nullptr };
};
With this a simple TestRunner:
main.cpp
#include <QApplication>
#include <QMenu>
#include <QAction>
#include "TriStateAction.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto label=new QLabel("Test");
label->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
label->connect(label, &QLabel::customContextMenuRequested, [&](const QPoint& point) {
QMenu menu(label);
auto globalPoint = label->mapToGlobal(point);
auto triStateAction = new TriStateAction();
auto normalAction = new QAction("Check");
normalAction->setCheckable(true);
normalAction->setChecked(true);
menu.addAction(triStateAction);
menu.addAction(normalAction);
menu.exec(globalPoint);
});
label->show();
app.exec();
}
Now, the context menu pops up and I can happily check, uncheck and partially check my TriState Action. But, unlike the ordinary QAction, the TriState will not close the menu upon interaction. How can this do?
Another issue is the different layout (visual representation) of my TriState Action. How can it be made more similar in comparison to the ordinary QAction? (Actually, this seems to be a very hard question.)
Let the action know its menu, adding this line in your main:
triStateAction->setMenu(&menu);
In TriStateAction class, add a slot to catch the check box stateChanged signal, and close the menu from there:
private slots:
void checkBoxStateChanged(int)
{
if (menu() != nullptr)
{
menu()->close();
}
}
Don't forget to connect the slot, in TriStateAction constructor:
connect(mChkBox, &QCheckBox::stateChanged, this, &TriStateAction::checkBoxStateChanged);
I made class inherited from QLabel. This class also have public slot, that should change label caption. I "call" this SLOT with clicked() SIGNAL of button.
So nothing happened when I press the button.
#include <QApplication>
#include <QLabel>
#include <QPushButton>
class Label : public QLabel
{
public:
Label(QString a) : QLabel(a){}
public slots:
void change()
{
this->setNum(2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("Button");
Label* lbl = new Label("Label");
button->show();
lbl->show();
QObject::connect(button, SIGNAL(clicked(bool)), lbl, SLOT(change()));
return a.exec();
}
What should I do to change caption from slot?
In order for the signals and slots to be recognized, the classes must use the Q_OBJECT macro in the private part.
Another thing to do is to include "main.moc", for more information on this point read this.
#include <QApplication>
#include <QLabel>
#include <QPushButton>
class Label : public QLabel
{
Q_OBJECT
public:
Label(const QString &text, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) :
QLabel(text, parent, f){}
public slots:
void change()
{
setNum(2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("Button");
Label* lbl = new Label("Label");
button->show();
lbl->show();
QObject::connect(button, SIGNAL(clicked()), lbl, SLOT(change()));
return a.exec();
}
#include "main.moc"
At the end of making these changes you must execute the following:
Press clean all in the Build menu.
then run qmake in the same menu.
And you just compose your project.
Add Q_OBJECT after
class Label : public QLabel
{
and then you should
either place your Label class declaration to a .h file or write #include "main.moc" after main function declaration.
try to get the return value from your connect call an check it for true or false.
Add Q_OBJECT Macro to the beginning of your derived class.
Add some debug output to your slot like
qDebug()<<"This is my slot.";
Maybe this would help to get a little further.
Best regards
I've just started to learn Qt and I want to make a simple program where I could select a picture name (in combobox) then click the pushbutton and selected picture would appear in widget(?) (in the same window if it's possible).
It should look like this:
The biggest problem that I've faced so far is connecting all those objects together, I can't make them work properly.
Also I've tried to upload picture to widget but it appears only in full size and my program becomes a picture and nothing else.
EDIT:
I am trying to make it work, but I can't achieve that..
That's my code:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_comboBox_currentIndexChanged(int index)
{
connect(ui->comboBox, SIGNAL(currentIndexChanged(int index)), this, SLOT(on_pushButton_clicked(int index)));
}
void MainWindow::choiceChanged(int index)
{
switch (index) {
case 0:
firstPicture();
break;
case 1:
secondPicture();
break;
case 2:
thirdPicture();
break;
}
}
void MainWindow::on_pushButton_clicked(int index)
{
connect(ui->pushButton, SIGNAL(on_pushButton_clicked(int)), this, SLOT(choiceChanged(int)));
}
void MainWindow::firstPicture(){
QPixmap image("C:/Documents/Aaaa.png");
ui->label->setPixmap(image);
}
void MainWindow::secondPicture(){
QPixmap image("C:/Documents/Bbbb.png");
ui->label->setPixmap(image);
}
void MainWindow::thirdPicture(){
QPixmap image("C:/Documents/Cccc.png");
ui->label->setPixmap(image);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked(int index);
void choiceChanged(int index);
void on_comboBox_currentIndexChanged(int index);
void firstPicture();
void secondPicture();
void thirdPicture();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Well your layout is ok but i suggest you use a QLabel to show the image.
So that's what I would do:
On the controller class create an attribute to store the current combo box selection, maybe an integer or a string.
connect to the signal changhed of the combobox a slot. (Easy way: right click on the combobox in the editor and select "Go to slot", then choose the currentIndexChanged(int index) or the string variation. See documentation)
In the slot keep our variable updated so that each time you change the value on the combobox you change also the variable that will store its current state.
Create a slot for the push button (same thing as the combobox. Use signal clicked()). In the slot you than insert te picture in the QLabel.
To set the picture do:
QPixmap image("/path/to/image/chosen/image.jpg"); //choose the path accordingly to the variable stored that mirrors the state of the combobox.
ui->imageLabel->setPixmap(image); //change imageLabel to the name of your label.
You are good to go.
I am trying to make a ruler in Qt. I am developing an application which requires a line edit in which the user can select any part of the string. When the selection is done, the start and end co-ordinates of the selection are passed to the backend.
The ruler which is shown with the line edit has a precision of one character or blank space in the string.
I have built a similar widget using Java and ExtJS some time ago. I am trying to simulate the same with Qt for quite some time now but not succeeding in doing so.
Please take a look at the image to understand what it looks like. I want to know whether it is possible or not in Qt. If it is possible what widget should I use to achieve it?
I am not 100% sure I understand your question correctly.
You can write a class inheriting from QLineEdit to emit signals when its selection has changed.
Below is a simple example of such a class: it takes the native signal selectionChanged and has two new signals which emit information about the changed text just to show what could be possible. I also include a simple dialog class to show how to use this (even if it's just a crude way).
lineedit.h
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
class LineEdit: public QLineEdit
{
Q_OBJECT
public:
LineEdit(QWidget *parent = 0): QLineEdit(parent)
{
connect(this, SIGNAL(selectionChanged()), this, SLOT(textSelectionChanged() ));
}
public slots:
void textSelectionChanged() {
emit selectionChanged(this->selectedText());
emit selectionChanged(this->selectionStart(), this->selectedText().length() );
}
signals:
void selectionChanged(const QString&);
void selectionChanged(int , int );
};
#endif
dialog.h
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include <QDialog>
#include <QtCore>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0) : QDialog(parent) {}
public slots:
void textChanged(const QString &string) {
qDebug() << string;
}
void textChanged(int start, int length) {
qDebug() << "Start"<< start << ", length: " << length;
}
};
#endif
main.cc (for completeness)
#include <QApplication>
#include "dialog.h"
#include "lineedit.h"
#include <QHBoxLayout>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Dialog dialog;
QHBoxLayout *layout = new QHBoxLayout(&dialog);
LineEdit lineedit;
layout->addWidget(&lineedit);
QObject::connect(&lineedit,SIGNAL(selectionChanged(QString)), &dialog, SLOT(textChanged(QString)));
QObject::connect(&lineedit,SIGNAL(selectionChanged(int,int)), &dialog, SLOT(textChanged(int,int)));
dialog.show();
return app.exec();
}
Let me know if this helps.