Below I present a full Qt project in which I was expecting to see a label and a button showing in a scrollarea, but it seems I'm not expressing myself as Qt expects. What Qt expects?
project.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = untitled13
TEMPLATE = app
SOURCES += main.cpp\
widget.cpp
HEADERS += widget.h
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QHBoxLayout>
#include <QScrollArea>
#include <QLabel>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *mainLayout = new QHBoxLayout(this);
QScrollArea *scrollArea = new QScrollArea;
mainLayout->addWidget(scrollArea);
QWidget *widget = new QWidget;
scrollArea->setWidget(widget);
QHBoxLayout *hLayout = new QHBoxLayout;
widget->setLayout(hLayout);
QLabel *label = new QLabel("somelable");
hLayout->addWidget(label);
QPushButton *bt = new QPushButton("click");
hLayout->addWidget(bt);
}
Widget::~Widget()
{
}
In this specific code the problem is that you call
scrollArea->setWidget(widget);
before you add layout of the widget. Move the above mentioned call to the end of the constructor and you see the label and the button inside the scrollarea.
It's also mentioned in the QScrollArea::setWidget documentation:
Note that You must add the layout of widget before you call this
function; if you add it later, the widget will not be visible -
regardless of when you show() the scroll area.
Related
My child widget does not get keyPressEvents, while if I put the same widget as top level window, it does. I try to set it get focus, but it has no effect on this. Code is below, showing what I try to get to work.
#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>
class DigitSummer: public QLCDNumber {
Q_OBJECT
public:
DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
}
protected:
void keyPressEvent(QKeyEvent *event) override {
display(intValue() + event->text().toInt());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#if 1 // this version does not work, number does not increase
QWidget widget;
widget.setLayout(new QVBoxLayout());
widget.layout()->addWidget(new QLabel("Press digits!"));
DigitSummer summer; // in stack: must be after widget to avoid child delete
widget.layout()->addWidget(&summer);
widget.setFocusProxy(&summer); // I notice no effect!
widget.show();
#else // this version works, number grows with keypresseas
DigitSummer summer;
summer.show();
#endif
return a.exec();
}
#include "main.moc"
And for completenes, .pro file for the same:
QT += core gui widgets
TARGET = QtMCVE
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11
QMAKE_CXXFLAGS += -Wall -Wextra
SOURCES += main.cpp
How to fix the widget to receive key events?
This related question suggests installing event filter, but I don't want to do that, there must be a self-contained way to fix the widget itself.
I think you need to set the focus policy for the widget before it will accept keyboard input. In your ctor try...
setFocusPolicy(Qt::StrongFocus);
Having said that, I'm really not sure why the behaviour would differ for top-level and non-top-level widgets.
Working version of the question code:
#include <QApplication>
#include <QKeyEvent>
#include <QLCDNumber>
#include <QLabel>
#include <QVBoxLayout>
class DigitSummer: public QLCDNumber {
Q_OBJECT
public:
DigitSummer(QWidget *parent = nullptr) : QLCDNumber(parent) {
setFocusPolicy(Qt::StrongFocus);
}
protected:
void keyPressEvent(QKeyEvent *event) override {
display(intValue() + event->text().toInt());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
widget.setLayout(new QVBoxLayout());
widget.layout()->addWidget(new QLabel("Press digits!"));
widget.layout()->addWidget(new DigitSummer);
widget.show();
return a.exec();
}
#include "main.moc"
I have to add a toolbar in Qt like the Windows file system explorer one under menu bar (I'm under Windows 7) , that means when the window width is reduced, icons which don't have enough place to be displayed are automatically hidden and put into a drop down list (which is displayed when clicking to an arrow which appears to the toolbar's right side). I first copy paste a code that I found to the web :
#include <QApplication>
#include <QAction>
#include <QMainWindow>
#include <QLineEdit>
#include <QToolBar>
#include <QHBoxLayout>
void initWindow(QMainWindow* w);
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(application);
QApplication app(argc, argv);
QMainWindow mainWin;
initWindow(&mainWin);
mainWin.show();
return app.exec();
}
void initWindow(QMainWindow* w)
{
QLineEdit* searchBar = new QLineEdit;
QAction* newAct = new QAction(QIcon(":/images/new.png"), "&New", w);
newAct->setShortcuts(QKeySequence::New);
QAction* openAct = new QAction(QIcon(":/images/open.png"), "&Open...", w);
openAct->setShortcuts(QKeySequence::Open);
QAction* saveAct = new QAction(QIcon(":/images/save.png"), "&Save", w);
saveAct->setShortcuts(QKeySequence::Save);
QAction* cutAct = new QAction(QIcon(":/images/cut.png"), "Cu&t", w);
cutAct->setShortcuts(QKeySequence::Cut);
QAction* copyAct = new QAction(QIcon(":/images/copy.png"), "&Copy", w);
copyAct->setShortcuts(QKeySequence::Copy);
QAction* pasteAct = new QAction(QIcon(":/images/paste.png"), "&Paste", w);
pasteAct->setShortcuts(QKeySequence::Paste);
QToolBar* fileToolBar = w->addToolBar("File");
fileToolBar->addAction(newAct);
fileToolBar->addAction(openAct);
fileToolBar->addAction(saveAct);
QToolBar* editToolBar = w->addToolBar("Edit");
editToolBar->addAction(cutAct);
editToolBar->addAction(copyAct);
editToolBar->addAction(pasteAct);
editToolBar->addWidget(searchBar);
}
... but the problem is that code works only for toolbars into a QMainWindow (and add by using QMainWindow::addToolbar() method). But into the code which I'm working for I have to do that into a QWidget, not a QWindow. So I created a horizontal layout, I added several widget into it (a QLineEdit and several QAction) and it works fine for QAction but not for QLineEdit : When I click to the arrow, all hidden QAction are visibles but not QLineEdit. Here is my code :
#include <QApplication>
#include <QtGui/QWindow>
#include <QToolbar>
#include <QVBoxLayout>
#include <QMainWindow>
#include <QPushButton>
#include <QAction>
#include <QIcon>
#include <QLineEdit>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget* w = new QWidget;
QHBoxLayout* tb1 = new QHBoxLayout;
tb1->addWidget(new QPushButton("item11"));
tb1->addWidget(new QPushButton("item12"));
tb1->addWidget(new QPushButton("item13"));
tb1->addWidget(new QPushButton("item14"));
QHBoxLayout* spacerLayout = new QHBoxLayout;
spacerLayout->addSpacerItem(new QSpacerItem(50, 20, QSizePolicy::MinimumExpanding,QSizePolicy::Fixed) );
spacerLayout->setAlignment(Qt::AlignJustify);
QWidget* sep = new QWidget;
QRect rect = sep->geometry();
rect.setWidth(0);
sep->setGeometry(rect);
QToolBar* tb3 = new QToolBar;
QLineEdit* searchBar = new QLineEdit;
QAction* item31 = new QAction(QIcon(":/images/cut.png"), "cut");
QAction* item32 = new QAction(QIcon(":/images/copy.png"), "copy");
QAction* item33 = new QAction(QIcon(":/images/open.png"), "open");
QAction* item34 = new QAction(QIcon(":/images/paste.png"), "past");
QAction* item35 = new QAction(QIcon(":/images/save.png"), "save");
tb3->addWidget(sep);
tb3->addWidget(searchBar);
tb3->addAction(item31);
tb3->addAction(item32);
tb3->addAction(item33);
tb3->addAction(item34);
tb3->addAction(item35);
QVBoxLayout* mainLayout = new QVBoxLayout;
QHBoxLayout* topLayout = new QHBoxLayout;
topLayout->addLayout(tb1);
topLayout->addLayout(spacerLayout);
topLayout->addWidget(tb3);
QHBoxLayout* bottomLayout = new QHBoxLayout;
bottomLayout->addWidget(new QPushButton);
mainLayout->addLayout(topLayout);
mainLayout->addLayout(bottomLayout);
w->setLayout(mainLayout);
w->show();
return app.exec();
}
These are screenshots of the result with the 2nd solution : I first launch application :
http://img4.hostingpics.net/pics/224120tb1.jpg
When I reduce its width, widgets which are to the right side disapeared. Then I click to the arrow to display them into the drop down list and they are all displayed except the QLineEdit :
http://img4.hostingpics.net/pics/903380tb2.jpg
Is someone here knows what the problem is ? Thanks.
Regrettably, tool bars only function correctly when embedded in a QMainWindow. The good news is that you can use a QMainWindow as if it were a widget. You can parent it to another widget, and then it won't be a standalone window. I've done this, and it works well. I was creating the objects using Qt Designer, and I had to remove the QMainWindow menu bar because Designer creates that automatically.
It's not an intuitive thing to do, but it works just fine, and it's a fairly easy change. A well-written comment explaining why you did that would probably be welcomed by anyone else reading the code in the future...
Thank you for your answer, I tried to test with a QMainWindow but it completely messed up the layout on which I worked and as it's a complex window (a lot of people worked on it in the past) and I have to finish my work soon I preferred to try a new approach. So after some research on the web I found that it's possible to do that I want even if the toolbar is not into a QMainWindow, but I have to replace all QWidget's that I want to have into QToolBar by a class which derived of QWidgetAction's, and instantiate them into QWidgetAction::createWidget() method. So I did this code which works correctly :
main.cpp :
#include <QApplication>
#include <QtGui/QWindow>
#include <QToolbar>
#include <QVBoxLayout>
#include <QMainWindow>
#include <QPushButton>
#include <QAction>
#include <QIcon>
#include <QLineEdit>
#include <QSlider>
#include <QVariant>
#include <QCheckBox>
#include <QWidgetAction>
#include "QMyWidgetAction.h"
void test2(QApplication& app);
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
test2(app);
return app.exec();
}
void test2(QApplication& app)
{
QWidget* w = new QWidget;
QHBoxLayout* l1 = new QHBoxLayout;
l1->addWidget(new QPushButton("item11"));
l1->addWidget(new QPushButton("item12"));
l1->addWidget(new QPushButton("item13"));
l1->addWidget(new QPushButton("item14"));
QHBoxLayout* l2 = new QHBoxLayout;
l2->addSpacerItem(new QSpacerItem(50, 20, QSizePolicy::MinimumExpanding,QSizePolicy::Fixed) );
l2->setAlignment(Qt::AlignJustify);
QHBoxLayout* l3 = new QHBoxLayout;
QToolBar* tb = new QToolBar;
l3->addWidget(tb);
QAction* item31 = new QAction(QIcon(":/images/cut.png"), "cut");
QAction* item32 = new QAction(QIcon(":/images/copy.png"), "copy");
QAction* item33 = new QAction(QIcon(":/images/open.png"), "open");
QAction* item34 = new QAction(QIcon(":/images/paste.png"), "past");
QAction* item35 = new QAction(QIcon(":/images/save.png"), "save");
QLineEdit* searchBar = new QLineEdit;
QMyWidgetAction* widgetAction = new QMyWidgetAction(tb);
QLineEditAction* lineEditAction = new QLineEditAction(tb);
tb->addSeparator();
tb->addWidget(searchBar);
tb->addAction(item31);
tb->addAction(item32);
tb->addAction(item33);
tb->addAction(item34);
tb->addAction(item35);
tb->addAction(widgetAction);
tb->addAction(lineEditAction);
QVBoxLayout* mainLayout = new QVBoxLayout;
QHBoxLayout* topLayout = new QHBoxLayout;
topLayout->addLayout(l1);
topLayout->addLayout(l2);
topLayout->addLayout(l3);
QHBoxLayout* bottomLayout = new QHBoxLayout;
bottomLayout->addWidget(new QPushButton);
mainLayout->addLayout(topLayout);
mainLayout->addLayout(bottomLayout);
w->setLayout(mainLayout);
w->show();
}
QMyWidgetAction.h :
#ifndef QMAYAWIDGETACTION_H
#define QMAYAWIDGETACTION_H
#include <QObject>
#include <QWidget>
#include <QWidgetAction>
class QLineEdit;
class QMyWidgetAction : public QWidgetAction
{
Q_OBJECT
public:
QMyWidgetAction(QWidget* parent);
QWidget* createWidget(QWidget* parent);
};
class QLineEditAction : public QWidgetAction
{
Q_OBJECT
public:
QLineEditAction(QWidget* parent);
QWidget* createWidget(QWidget* parent);
protected slots:
virtual void searchTextChanged(const QString& text);
private:
QLineEdit* fWidget;
};
#endif // QMAYAWIDGETACTION_H
QMyWidgetAction.cpp :
#include <QApplication>
#include <QtGui/QWindow>
#include <QToolbar>
#include <QVBoxLayout>
#include <QMainWindow>
#include <QPushButton>
#include <QAction>
#include <QIcon>
#include <QLineEdit>
#include <QSlider>
#include <QVariant>
#include <QCheckBox>
#include <QWidgetAction>
#include "QMyWidgetAction.h"
QMyWidgetAction::QMyWidgetAction(QWidget* parent)
: QWidgetAction(parent)
{
}
QWidget* QMyWidgetAction::createWidget(QWidget* parent)
{
QPushButton* widget = new QPushButton("bouton", parent);
widget->setMinimumSize(100, 30);
return widget;
}
QLineEditAction::QLineEditAction(QWidget* parent)
: QWidgetAction(parent)
{
}
QWidget* QLineEditAction::createWidget(QWidget* parent)
{
fWidget = new QLineEdit(parent);
connect(fWidget, SIGNAL(textChanged(QString)), this, SLOT(searchTextChanged(QString)));
fWidget->setMinimumSize(100, 30);
return fWidget;
}
void QLineEditAction::searchTextChanged(const QString& text)
{
fWidget->setMinimumWidth(fWidget->minimumWidth() + 10);
}
So now here is what I get when I reduce the window width :
So the result is correct (and controls works, I tested them), but now I would like to know if it's possible to display the extension list horizontally instead of vertically ? (I mean "past" action at the right of "open" action, "save" action at the right of past action etc.) Thanks for your help.
I would like to use a custom made QWidget in one row of a QFormLayout. The code below presents a form layout in which the first row has a a QLineEdit and the second line has a custom made widget:
The problem is that the custom made widget is not vertically aligned. How to align it vertically?
project.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = CustomLineEdit
TEMPLATE = app
SOURCES += main.cpp
main.cpp
#include <QApplication>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QLineEdit>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QFormLayout *formLayout = new QFormLayout(&w);
QLineEdit *leUser = new QLineEdit;
QWidget *widget = new QWidget;
QHBoxLayout *hLayout = new QHBoxLayout(widget);
hLayout->addWidget(leUser);
hLayout->addWidget(new QPushButton);
formLayout->addRow("Text:", new QLineEdit);
formLayout->addRow("User:", widget);
w.show();
return a.exec();
}
This is because of margins. Just add followed line:
QHBoxLayout *hLayout = new QHBoxLayout(widget);
hLayout->setMargin(0); //this line
I'm trying to write application's menu for my text editor, but I don't understand why signal triggered does not working. It should open a QFileDialog::getOpenFileName, but it does not happen. Why?
main.cpp
#include "mainwindow.h"
#include "centralwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *mainWindow = new MainWindow;
CentralWidget *centralWidget = new CentralWidget;
mainWindow->setCentralWidget(centralWidget);
mainWindow->show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QStatusBar>
#include <QAction>
#include <QFileDialog>
#include <QString>
class MainWindow : public QMainWindow
{
public:
MainWindow();
public slots:
void slotFileDialog();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow()
{
QMenu *fileMenu = new QMenu("File");
QAction *openAction = new QAction(tr("&Open..."), this);
connect(openAction, SIGNAL(triggered()),
this, SLOT(slotFileDialog()));
fileMenu->addAction(openAction);
QMenuBar *mainMenu = new QMenuBar;
mainMenu->addMenu(fileMenu);
mainMenu->show();
QStatusBar *mainStatusBar = new QStatusBar;
setMenuBar(mainMenu);
setStatusBar(mainStatusBar);
}
void MainWindow::slotFileDialog()
{
QString fileName = QFileDialog::getOpenFileName(
this, tr("Open File"),"/home",tr("Text (*.txt)"));
}
You haven't included the Q_OBJECT macro in the class definition, so the moc will not generate the associated files for it.
How i can add QRadioButtons in a QFrame on runtime?
Thanks.
Add the widget to the appropriate place by calling the addWidget() method, such as:
ui->someLayout->addWidget(widgetToAdd);
Just make sure you do this in your main (UI) thread.
you can add a QRadioButtons on runtime normally in the same way you do before runtime.
you create the QRadioButton dynamically and call the addWidget method of QFrame layout.
if you are not ableto do it, post the code and let me show you.
mainwindow.h
#include <QtGui/QMainWindow>
#include <QPushButton>
#include <QHBoxLayout>
#include <QRadioButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
QHBoxLayout * layout;
QPushButton * button;
public:
MainWindow(QWidget *parent = 0);
public slots:
void radioAdd();
};
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
layout = new QHBoxLayout(this);
QWidget * w = new QWidget(this);
w->setLayout(layout);
this->setCentralWidget(w);
button = new QPushButton(QString("push"),this);
layout->addWidget(button);
connect(button,SIGNAL(clicked()), this, SLOT(radioAdd()));
}
void MainWindow::radioAdd() {
QRadioButton * radio = new QRadioButton("Search from the &cursor", this);
layout->addWidget(radio);
}
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
in this code the radioButton get created in the runtime (in the slot function radioAdd). and in your case, instead of adding QRadioButton into the wigdet layout you add them into QFrame.