I'm writing newbie Qt5(.4.0) code on OSX Mavericks. Here's my self-contained test case:
#include <QApplication>
#include <QMainWindow>
#include <QtGui>
#include <QMenuBar>
#include <QGridLayout>
#include <QPushButton>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
mw->menuBar()->setNativeMenuBar( false );
QMenu* fileMenu = mw->menuBar()->addMenu( "&File" );
QMenu* optionsMenu = mw->menuBar()->addMenu( "&Options" );
QWidget* menuCorner = new QWidget( mw->menuBar() );
QGridLayout* cornerLayout = new QGridLayout();
QPushButton* newWindowButton = new QPushButton( "New Window" );
cornerLayout->addWidget( newWindowButton, 1, 0 );
menuCorner->setLayout( cornerLayout );
mw->menuBar()->setCornerWidget( menuCorner );
mw->show();
return app.exec();
}
The "New Window" pushbutton shows up at the right side of the menubar, as intended, however the bottom half of the "New Window" pushbutton is clipped, and thus hidden, by the bottom separator line for the menubar:
How can I make the new corner-widget pushbutton appear fully in the menubar without getting clipped?
Thanks
OSX menu bars must have a fixed height and your button doesn't fit there. Try to remove layout margins:
cornerLayout->setContentsMargins(0, 0, 0, 0);
And / or make the button smaller:
newWindowButton->setMaximumHeight(30);
Also, adjust margin to what best fits your needs:
menuCorner->setStyleSheet("margin-top: 2");
This is how it looks for me:
Related
I have a Qt5.11.0 application (on OSX10.13 and CentOS7.4) with multiple QMainWindows. I would like users to be able to dock any given QDockWidget in the application into any of the QMainWindow instances.
The sample code below shows an application with two QMainWindows and one QDockWidget. I can undock and re-dock the QDockWidget from and to the first QMainWindow to which it was attached, however if I hover the detached QDockWidget over the second QMainWindow, the QDockWidget and the second QMainWindow ignore each other, rather than docking together as hoped:
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QLabel>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw1 = new QMainWindow();
QMainWindow* mw2 = new QMainWindow();
mw1->setWindowTitle( "Main Window 1" );
mw2->setWindowTitle( "Main Window 2" );
mw1->setCentralWidget( new QWidget() );
mw2->setCentralWidget( new QWidget() );
QDockWidget* dockWidget = new QDockWidget( "Stepchild", mw1 );
QLabel* label = new QLabel( "Hello World" );
dockWidget->setWidget( label );
mw1->addDockWidget( Qt::LeftDockWidgetArea, dockWidget );
mw1->show();
mw2->show();
QRect first = mw1->geometry();
int pixeloffset = 200;
mw2->setGeometry( first.x() + pixeloffset,
first.y() + pixeloffset,
first.width(),
first.height() );
return app.exec();
}
How can I allow my QDockWidget above to dock in any of the QMainWindows in the application?
Thanks --
I have the following Qt5.11.0 code to create a qdockwidget. The nature of the widget is such that it makes sense to allow the user to interactively resize the widget, via mouse, as desired when the dockwidget is floating (the example below is contrived, but I believe illustrates the problem).
When I run this and float the dockwidget into its own top-level window, it turns out to be either very hard (Linux) or impossible (OSX) to resize the dockwidget via user interaction. On RHEL Linux 7.6, hovering the mouse over the lower right corner of the floating dockwidget produces a 'resize' cursor, however the hot-spot for such behavior is at best one or two pixels wide, making it very hard and frustrating for users to resize the floating dockwidgets. On OSX 10.13.6, I do not see any option to resize the dockwidget at all via mouse interaction.
Here is the example code:
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QTextEdit>
#include <QTextStream>
#include <QFile>
#include <QSizeGrip>
int
main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
mw->setCentralWidget( new QWidget() );
QDockWidget* dockWidget = new QDockWidget( "Code viewer", mw );
mw->addDockWidget( Qt::LeftDockWidgetArea, dockWidget );
QTextEdit* textEdit = new QTextEdit( dockWidget );
dockWidget->setWidget( textEdit );
QFile file( "/etc/protocols" );
QString filler;
if( ! file.open( QIODevice::ReadOnly ) ) {
exit( -1 );
} else {
QTextStream in( &file );
while( ! in.atEnd() ) {
filler += in.readLine();
}
file.close();
}
textEdit->setText( filler );
mw->show();
return app.exec();
}
I've experimented with QSizeGrip() and searched all over the net, but so far to no avail.
How do I control the hot-zone size for mouse-driven floating dockwidget resizing with Qt on Linux, and how do I enable such in the first place with Qt on OSX?
Unfortunately, the border of a detached QDockWidget is handled by the window decorator, so you can't change it by stylesheets or adjusting the size grip.
Anyway, you can change the dock widget's window flags to force the window decorator to draw regular borders.
Here is an how you can do it in your example:
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>
#include <QTextEdit>
#include <QTextStream>
#include <QFile>
#include <QSizeGrip>
int main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QMainWindow* mw = new QMainWindow();
mw->setCentralWidget( new QWidget() );
QDockWidget* dockWidget = new QDockWidget( "Code viewer", mw );
mw->addDockWidget( Qt::LeftDockWidgetArea, dockWidget );
// handle floating changes
QObject::connect(dockWidget, &QDockWidget::topLevelChanged, [dockWidget] (bool floating)
{
if (floating)
{
dockWidget->setWindowFlags(Qt::Window);
dockWidget->show();
}
});
QTextEdit* textEdit = new QTextEdit( dockWidget );
dockWidget->setWidget( textEdit );
QFile file( "/etc/protocols" );
QString filler;
if( ! file.open( QIODevice::ReadOnly ) ) {
exit( -1 );
} else {
QTextStream in( &file );
while( ! in.atEnd() ) {
filler += in.readLine();
}
file.close();
}
textEdit->setText( filler );
mw->show();
return app.exec();
}
Here you can find a description of all the available window flags to customize the look of your widget.
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 need a pushbutton to either fill or not fill the entire space provided by a QGridLayout cell upon the creation of the button (the alignment value is loaded from file). I've simplified my situation with the following code. During run-time, users can set the alignment of the button - either making it fill the entire layout cell or nicely centered. It works so long as the button didn't start off with NULL alignment specified. Yet, I need the ability to start off with a NULL alignment (i.e. the button fills the space of the layout cell). When initially aligning with NULL, what is getting set to make the button lock into a AlignVCenter setting and how can I get the button to return to acting like it was initialized with something other than null alignment?
I'm using Qt 4.8 on Ubuntu 12.04 LTS
#include <QPushButton>
#include <QGridLayout>
#include <QMainWindow>
#include <QApplication>
class MyWidget : public QWidget {
Q_OBJECT
QPushButton* m_pb;
QGridLayout* m_gl;
protected slots:
void pbClicked();
public:
MyWidget(QWidget* parent = 0);
};
MyWidget::MyWidget(QWidget* parent): QWidget(parent)
{
m_pb = new QPushButton(tr("push me"));
connect(m_pb, SIGNAL(clicked()), this, SLOT(pbClicked()));
m_gl = new QGridLayout();
//use (1) to see button expand when button is pressed
//use (2) to show that I can't start off expanded
/*1*/ //m_gl->addWidget(m_pb, 0, 0, Qt::AlignCenter); // creates desired effect
/*2*/ //m_gl->addWidget(m_pb, 0, 0, 0); //does not create desired effect
setLayout(m_gl);
}
void MyWidget::pbClicked(){
//will expand button so long as initial alignment is not NULL
m_gl->setAlignment(m_pb, 0);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyWidget* widget = new MyWidget();
QMainWindow window;
window.setCentralWidget(widget);
window.show();
return app.exec();
}
#include "main.moc"
The "desired" behavior that you see is in fact an error, and I will file a bug report for it. Thanks for spotting it - nice corner case.
You need to set the size policy of the button to expanding in both directions. Buttons normally don't want to expand vertically, so if you tried a variant that toggles the alignment, you'd see that it works only horizontally, and that's correct.
This is a simple demonstration that shows the correct behavior that also fulfills your needs.
#include <QPushButton>
#include <QGridLayout>
#include <QApplication>
class AlignButton : public QPushButton {
Q_OBJECT
Qt::Alignment m_alignment;
Q_SLOT void clicked() {
m_alignment ^= Qt::AlignCenter;
parentWidget()->layout()->setAlignment(this, m_alignment);
label();
}
void label() {
setText(QString("Alignment = %1").arg(m_alignment));
}
public:
AlignButton(Qt::Alignment alignment, QWidget * parent = 0) :
QPushButton(parent),
m_alignment(alignment)
{
connect(this, SIGNAL(clicked()), SLOT(clicked()));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
label();
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
QGridLayout layout(&window);
layout.addWidget(new AlignButton(0), 0, 0, 0);
layout.addWidget(new AlignButton(Qt::AlignCenter), 1, 0, Qt::AlignCenter);
window.setMinimumSize(500, 200);
window.show();
return app.exec();
}
#include "main.moc"
I have a qlabel L inside a qwidget W. L is vertically and horizontally aligned.
When I resize W, L doesn't get centered.
Is this expected?
What's a good implementation to have L centered again?
To align text in a QLabel by calling QLabel::setAlignment works like expected for me.
Maybe you miss to add your Label to a Layout (so your label would automatically resized if your widget is resized). See also Layout Management. A minimal example:
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QWidget>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QLabel* label=new QLabel("Hello World!");
label->setAlignment(Qt::AlignCenter);
QWidget* widget=new QWidget;
// create horizontal layout
QHBoxLayout* layout=new QHBoxLayout;
// and add label to it
layout->addWidget(label);
// set layout to widget
widget->setLayout(layout);
widget->show();
return app.exec();
}