QDialog with floating toolbar - qt

How can I create a QDialog with floating toolbar in Qt?
Attachment of the QMainWindow with toolbar as widget in the QDialog is not suitable.

Why not suitable? following code works like charms.
#include <QtGui>
class MyDialog : public QDialog
{
Q_OBJECT
public:
MyDialog(QWidget* parent=0)
{
QMainWindow* child = new QMainWindow;
QLabel* label = new QLabel(tr("QMainWindow with toolbar!"));
label->setAlignment(Qt::AlignCenter);
child->setCentralWidget(label);
QToolBar* toolbar = child->addToolBar(tr("Tool"));
toolbar->addAction(tr("Test"), this, SLOT(doTest()));
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setContentsMargins(0,0,0,0);
layout->addWidget(child);
}
private slots:
void doTest()
{
QMessageBox::information(this, tr("Test"), tr("ToolBar is Working!"));
}
};

look at
Can you add a toolbar to QDialog?
and try to write smth like that
myDialog->layout()->setMenuBar(myToolBar);

Related

How to properly delete items from the QWidget

This is the code for populating and deleting item from the QWidget.
class ShowCommands : public QWidget
{
private:
QWidget wdg;
QVBoxLayout m_layout;
QScrollArea* m_area;
QWidget m_contents;
QVBoxLayout m_contentsLayout;
bool isWrite;
public:
ShowCommands(QWidget *parent = nullptr);
void showWindow();
void setParent(QWidget* par);
void AddCommand(std::string stdstrCommand);
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ShowCommands::ShowCommands(QWidget *parent) : QWidget(parent)
{
isWrite = true;
m_area = new QScrollArea;
m_contents.setLayout(&m_contentsLayout);
m_layout.addWidget(m_area);
m_area->setWidget(&m_contents);
m_contentsLayout.setSizeConstraint(QLayout::SetMinimumSize);
wdg.setLayout(&m_layout);
wdg.setFixedWidth(650);
wdg.setWindowTitle("Commands");
wdg.setWindowFlags(Qt::Window
| Qt::FramelessWindowHint);
wdg.hide();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ShowCommands::showWindow()
{
if (isWrite == false)
{
if (m_contentsLayout.layout() != NULL)
{
QLayoutItem* item;
while ((item = m_contentsLayout.layout()->takeAt(0)) != NULL)
{
delete item->widget();
delete item;
}
}
isWrite = true;
wdg.show();
// AddCommand() function is called now multiple times and items are populated.
}
else
{
isWrite = false;
wdg.hide();
}
}
void ShowCommands::AddCommand(std::string stdstrCommand)
{
if (isWrite)
{
QLabel *label = new QLabel;
label->setText(stdstrCommand.c_str());
m_contentsLayout.addWidget(label);
}
}
In the showWindow() function first all of the items of widget are deleted and than populate the widget with new items.
The issue is that after i delete the existing items the new items are not populated from top to bottom but they start appearing from center.
I see many problems with your code, some of them make it hard to read, but anyway I think the main problem here is how properly create those items ...
You should create your widgets as pointers and assign good parenting to them, unparented widgets will create a new window. You should do something like this.
class MyWidget: public QWidget
{
Q_OBJECT
public;
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
{
w1=new QWidget(this);
}
private:
class QWidget *m_w1;
}
that way you will have a child widget that will be drawn relative to you in the same window. You can add a layout to your widget, and then add your widgets to it so it handles the location for you. ie:
class MyWidget: public QWidget
{
Q_OBJECT
public;
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
{
//passing this to the construct assign layout to 'this' widget
QVBoxLayout *verticalLayout=new QVBoxLayout(this);
w1=new QWidget(this);
w2=new QWidget(this);
verticalLayout->addWidget(w1);
verticalLayout->addWidget(w2);
}
private:
class QWidget *m_w1;
class QWidget *m_w2;
}
in that case both widgets will be display one below the other in the space assigned to you. Also the space assigned to you will depend on the characteristics of the two child widgets (you probably will create something derived from QWidget).
Now about the QScrollArea, that widget it is meant to be used with a widget placed 'inside', and you should add items to the layout of that one. ie:
class MyWidget: public QWidget
{
Q_OBJECT
public;
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
{
//passing this to the construct assign layout to 'this' widget
QVBoxLayout *verticalLayout=new QVBoxLayout(this);
m_scroll=new QScrollArea(this);
verticalLayout->addWidget(m_scroll);
m_containerwidget=new QWidget(this);
//this sets our container widget as the inside's scrollarea widget
m_scroll->setWidget(m_containerwidget);
//if your widget will resize along the way you use this, in your case you do
m_scroll->setWidgetResizable(true);
m_containerLayout=new QVBoxLayout (m_containerwidget);
m_w1=new QWidget(this);
m_w2=new QWidget(this);
m_containerLayout->addWidget(m_w1);
m_containerLayout->addWidget(m_w2);
}
private:
class QScrollArea *m_scroll;
class QWidget *m_containerwidget;
class QVBoxLayout *m_containerLayout;
class QWidget *m_w1,m_w2;
}
You don't usually store all that information (m_containerLaoyut,m_containerWidget) in the class as you can query the objects for them, but just for clarity I add them there.
The last example applies to your scenario, you could store your 'items widgets' in a list, or query the layout for them, and when you need to delete them you just do that and then add new ones to the layout.
Of course you can use any kind of layout, I used vertical just as an example.

Qt placing widget on custom place

I need to place(programmaticaly) my custom widget in specified place in my MainWindow.
On screenshoot I've marked red rectangle "widget" on place where I want to place my widget. I want place widget on top of QmenuBar and QToolBar.
I've tried setCentralWidget, but it expands widget on whole window.
Image presenting my problem
Code of my widget:
timers.cpp
#include "QtWidgets"
#include "timers.h"
static QLabel *createDragLabel(const QString &text, QWidget *parent)
{
QLabel *label = new QLabel(text, parent);
label->setAutoFillBackground(true);
label->setFrameShape(QFrame::Panel);
label->setFrameShadow(QFrame::Raised);
return label;
}
Timers::Timers(QWidget *parent) : QWidget(parent)
{
QLabel *wordLabel = createDragLabel("dupppa", this);
}
mainwindow.cpp
MainWindow::MainWindow()
{
initMenu();
initButtons();
TrackWindow *trackWindow = new TrackWindow();
setCentralWidget(trackWindow);
Timers *firstTimer = new Timers();
//setCentralWidget(firstTimer); // suck
}
Ok, here is a solution: make MainWidget to be a parent of your widget but do not add it to parent layout. Then basically move your widget with QWidget::move() and and set its size with QWidget::resize(). This way you get a widget with absolute location.
An extract of working code:
#include <QLayout>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow{ parent },
ui{ new Ui::MainWindow }
{
ui->setupUi(this);
menuBar = new QMenuBar { this };
toolBar = new QToolBar { this };
textEdit = new QTextEdit { this };
menuBar->addMenu("File");
menuBar->addMenu("Edit");
menuBar->addMenu("About");
toolBar->addAction("Copy");
toolBar->addAction("Cut");
toolBar->addAction("Insert");
toolBar->addAction("Other tools");
layout()->setMenuBar(menuBar);
addToolBar(toolBar);
textEdit->setText("Your widget");
textEdit->resize(90, 30);
textEdit->move(250, 10);
}
A screenshot:

Convert QStackedLayout to QHBoxLayout dynamically

I would like to change my widget layout from QStackedLayout to QHBoxLayout to QVBoxLayout dynamically by clicking on push buttons. I am able to switch from QVBoxLayout to QHBoxLayout and vice versa, but my approach does not work for QStackedLayout. I've exhausted all options I can think of. A sample code is attached. Does anyone know how I can achieve my objective?
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QStackedLayout>
#include <QGridLayout>
#include <QLabel>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
QPushButton *button1_;
QPushButton *button2_;
QPushButton *button3_;
QHBoxLayout *hLayout_;
QVBoxLayout *vLayout_;
QStackedLayout *sLayout_;
QVBoxLayout *gLayout_;
public slots:
void layoutHorizontal();
void layoutVertical();
void layoutStacked();
private:
bool isStackedLayout_;
QLabel *bar_;
};
#endif // WIDGET_H
#include "widget.h"
#include <QtAlgorithms>
#include <QDebug>
Widget::Widget(QWidget *parent) : QWidget(parent){
bar_ = new QLabel(tr("TEST!"));
button1_ = new QPushButton(tr("to Horizontal Layout"),(bar_));
button2_ = new QPushButton(tr("to Vertical Layout"),(bar_));
button3_ = new QPushButton(tr("to Stacked Layout"),(bar_));
button1_->setStyleSheet("background: rgba(255,255,0,255);");
button2_->setStyleSheet("background: rgba(255,0,255,255);");
button3_->setStyleSheet("background: rgba(0,255,255,255);");
connect(button1_,SIGNAL(clicked()),this,SLOT(layoutHorizontal()));
connect(button2_,SIGNAL(clicked()),this,SLOT(layoutVertical()));
connect(button3_,SIGNAL(clicked()),this,SLOT(layoutStacked()));
gLayout_ = new QVBoxLayout;
setLayout(gLayout_);
hLayout_ = new QHBoxLayout(bar_);
hLayout_->setObjectName(tr("currentLayout"));
gLayout_->addWidget(bar_);
hLayout_->addWidget(button1_);
hLayout_->addWidget(button2_);
hLayout_->addWidget(button3_);
isStackedLayout_ = false;
resize(480,200);
}
Widget::~Widget() { }
void Widget::layoutHorizontal(){
QLayout *layout = bar_->findChild<QLayout *>(tr("currentLayout"));
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
delete layout;
QHBoxLayout *hLayout_ = new QHBoxLayout(bar_);
hLayout_->setObjectName(tr("currentLayout"));
hLayout_->addWidget(button1_);
hLayout_->addWidget(button2_);
hLayout_->addWidget(button3_);
isStackedLayout_ = false;
}
void Widget::layoutVertical(){
QLayout *layout = bar_->findChild<QLayout *>(tr("currentLayout"));
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
delete layout;
QVBoxLayout *vLayout_ = new QVBoxLayout(bar_);
vLayout_->setObjectName(tr("currentLayout"));
vLayout_->addWidget(button1_);
vLayout_->addWidget(button2_);
vLayout_->addWidget(button3_);
isStackedLayout_ = false;
}
void Widget::layoutStacked(){
QLayout *layout = bar_->findChild<QLayout *>(tr("currentLayout"));
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
delete layout;
QStackedLayout *sLayout_ = new QStackedLayout(bar_);
sLayout_->setObjectName(tr("currentLayout"));
sLayout_->addWidget(button1_);
sLayout_->addWidget(button2_);
sLayout_->addWidget(button3_);
isStackedLayout_ = true;
}
The visibility property on your buttons gets set to "invisible" after pulling widgets out of the QStackedLayout (likely because the QStackedLayout relies on this property to emulate stacking). As such, I was able to get your code to work by adding the following:
void Widget::layoutHorizontal() {
...
button1_->setVisible(true);
button2_->setVisible(true);
button3_->setVisible(true);
isStackedLayout_ = false;
}
It's also worth noting that removing the widgets from the layout prior to deleting it is not necessary. The layout doesn't take ownership of the widgets in it. As such you can delete the following:
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
Create another widget with only widgets and one layout inside. Then use setLayout for your widget. Sorry for my bad C++ knowledge :)
class ChangeableWidget: public QWidget {
private QVBoxLayout vbox;
private QHBoxLayout hbox;
private QStackedLayout stacked;
private QPushButton button1;
private QPushButton button2;
ChangeableWidget()
{
button1 = new QPushButton("1");
button2 = new QPushButton("2");
vbox = new QVBoxLayout();
vbox.addWidget(button1);
vbox.addWidget(button2);
hbox = new QHBoxLayout();
hbox.addWidget(button1);
hbox.addWidget(button2);
stacked = new QStackedLayout();
stacked.addWidget(button1);
stacked.addWidget(button2);
setLayout(vbox);
}
void ChangeableWidget::layoutVertical()
{
setLayout(vbox);
}
void ChangeableWidget::layoutHorizontal()
{
setLayout(hbox);
}
}

change text of QLabel in another class with button

I have ever post a question at there: change text in another class by button But it justs working when second class is create by first class. Now I have 2 classes, they're created sametime, so how to I connect with together? below is all my code, first class has a button, and second class has a label, I want to when user click on the button in first class, label in second class will be changed. They're put in stackWidget:
// file.h
#include <QWidget>
#include <QtGui>
class widgetA;
class widgetB;
class A : public QWidget
{
Q_OBJECT
public:
explicit A(QWidget *parent = 0);
private:
QComboBox* comboBox;
QStackedWidget* stackWidget;
widgetA *wa;
widgetB *wb;
};
class widgetA : public QWidget
{
Q_OBJECT
public:
widgetA(QWidget *parent = 0);
public slots:
void buttonClicked();
private:
QPushButton* button;
};
class widgetB : public QWidget
{
Q_OBJECT
public slots:
void labelChangeText(const QString);
public:
widgetB(QWidget *parent = 0);
QLabel* label;
};
And this's cpp file:
//file.cpp
#include "a.h"
A::A(QWidget *parent) :
QWidget(parent)
{
comboBox = new QComboBox(this);
comboBox->addItem(tr("Widget A"));
comboBox->addItem(tr("Widget B"));
wa = new widgetA(this);
wb = new widgetB(this);
stackWidget = new QStackedWidget(this);
stackWidget->addWidget(wa);
stackWidget->addWidget(wb);
stackWidget->setCurrentIndex(0);
connect(comboBox, SIGNAL(currentIndexChanged(int)), stackWidget, SLOT(setCurrentIndex(int)));
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(comboBox);
layout->addWidget(stackWidget);
setLayout(layout);
}
widgetA::widgetA(QWidget *parent):
QWidget(parent)
{
button = new QPushButton(tr("Click"));
connect(button, SIGNAL(clicked()), this, SLOT(buttonClicked()));
QHBoxLayout* lay = new QHBoxLayout;
lay->addWidget(button);
setLayout(lay);
}
void widgetA::buttonClicked()
{
// what I have to do at there for call the function at widgetB class?
}
widgetB::widgetB(QWidget *parent):
QWidget(parent)
{
label = new QLabel("....");
QHBoxLayout* lay = new QHBoxLayout;
lay->addWidget(label);
setLayout(lay);
}
void widgetB::labelChangeText(const QString text)
{
label->setText(text);
}
P/S: sorry my english
You can either pass a pointer of widgetB object to widgetA, or you can connect a signal from widgetA to a slot in widgetB.
Here's an example of the signal/slot option:
// widgeta.h
signals:
void changeText(QString text);
-
// widgeta.cpp
void widgetA::buttonClicked()
{
emit changeText("button clicked");
}
-
//widgetb.h
public slots:
void labelChangeText(const QString & text);
-
// a.cpp
connect(wa, SIGNAL(changeText(QString)), wb, SLOT(labelChangeText(QString)));
What hinders you to call wb->labelChangeText("some string") in widgetA::buttonClicked()? You have a pointer to widgetB in class A. And labelChangeText is public in class B. Just that it is a slot does not mean that you cannot call it as a normal method.

Adding drop down menu to Qt GUI - error 'menubar' no declared

I'm trying to create a menu in Qt following this example http://doc.qt.nokia.com/latest/mainwindows-menus.html
but I keep getting the error 'menuBar' not declared in this scope
void Window::createMenus()
{
saveMenu = menuBar()->addMenu("&Save");
}
In context:
#include <QtGui>
#include "borderlayout.h"
#include "window.h"
Window::Window()
{
QTextBrowser *centralWidget = new QTextBrowser;
//***Change this to whatever widget(s) the drawing area is. QPainter or something?
centralWidget->setPlainText(tr("DRAW HERE YAY"));
BorderLayout *layout = new BorderLayout;
layout->addWidget(centralWidget, BorderLayout::Center);
layout->addWidget(createLabel("File ..."), BorderLayout::North);
layout->addWidget(createLabel("Toolbar yo!"), BorderLayout::West);
//layout->addWidget(createLabel("Status bar"), BorderLayout::South);
//Maybe we could put in a status bar. For now let's not worry about it. It's not a requirement.
setLayout(layout);
createMenus();
setWindowTitle(tr("Border Layout"));
}
QLabel *Window::createLabel(const QString &text)
{
QLabel *label = new QLabel(text);
label->setFrameStyle(QFrame::Box | QFrame::Raised);
return label;
}
void Window::createMenus()
{
saveMenu = menuBar()->addMenu("&Save");
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
class QLabel;
class QMenu;
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private:
void createMenus();
QLabel *createLabel(const QString &text);
QMenu *saveMenu();
};
#endif
window.cpp
#include <QtGui>
#include "borderlayout.h"
#include "window.h"
Window::Window()
{
QTextBrowser *centralWidget = new QTextBrowser;
//***Change this to whatever widget(s) the drawing area is. QPainter or something?
centralWidget->setPlainText(tr("DRAW HERE YAY"));
BorderLayout *layout = new BorderLayout;
layout->addWidget(centralWidget, BorderLayout::Center);
layout->addWidget(createLabel("File ..."), BorderLayout::North);
layout->addWidget(createLabel("Toolbar yo!"), BorderLayout::West);
//layout->addWidget(createLabel("Status bar"), BorderLayout::South);
//Maybe we could put in a status bar. For now let's not worry about it. It's not a requirement.
setLayout(layout);
createMenus();
setWindowTitle(tr("Border Layout"));
}
QLabel *Window::createLabel(const QString &text)
{
QLabel *label = new QLabel(text);
label->setFrameStyle(QFrame::Box | QFrame::Raised);
return label;
}
void Window::createMenus()
{
saveMenu = menuBar()->addMenu("&Save");
}
The menu bar is a feature of the QMainWindow class.
Because your Window class is being inherited directly from QWidget, it does not have the menuBar method, hence your error.
You need to subclass your Window class from QMainWindow rather than QWidget.

Resources