Docking a QDockWidget when application starts? - c++

I have a class that constructs a widget that I am able to dock into my main application. This class inherits QDockWidget. This allows me to dock the widget if I so please. However, I would like for this widget to be docked by default instead of showing up as a separate floating window.
To give you an idea of how this class is laid out, here is the header for it. Consider that I want to keep the log and showMessage functions.
Logger.h
class Logger : public QDockWidget
{
Q_OBJECT
public:
explicit Logger(QWidget* parent = 0);
void log(QString message);
~Logger();
private:
QWidget* dockWidgetContents;
QGridLayout* gridLayout;
QTextEdit* LoggerEdit;
void showMessage(QString &message);
};
#endif // MESSAGES_H
In the .cpp file for my main application, I use loggerWidget = new Logger(this);. This works, and when I open my application, the Logger widget pops up. I can then dock it into the sides of the main window on any side.
The problem I run into is getting this widget to be docked to the right side of the main window upon opening.
I've looked around for a solution and found that something similar to the following should work in the main window .cpp file. I just don't know how to implement it correctly.
LoggerWidget = new Logger(this);
this->setWidget(LoggerWidget);
addDockWidget(Qt::RightDockWidgetArea, LoggerWidget);
LoggerWidget->setFloating(false);
I think the issue is that since my Logger class is inheriting QDockWidget but isn't actually a QDockWidget, so I can't just do an addDockWidget in the main .cpp file.
How can I make this work while keeping the functionality that the class provides?

Assuming that the second pice of code:
LoggerWidget = new Logger(this);
this->setWidget(LoggerWidget);
addDockWidget(Qt::RightDockWidgetArea, LoggerWidget);
LoggerWidget->setFloating(false);
is within the constructor of a class that inherits from QMainWindow (otherwise you will not have functionalities such as addDockWidget), you can expect a weird behaviour if you execute this code because you are adding the same widget (LoggerWidget) to the central part of the window as well as to the dockable area (if it works you will see the exact same thing in both). Please find in the attached code a simple example of a QMainWindow with a central widget and a docked widget that inherits from QDockWidget:
Logger header
#ifndef LOGGER_H
#define LOGGER_H
#include <QDockWidget>
#include <QTextEdit>
class Logger : public QDockWidget
{
Q_OBJECT
public:
explicit Logger(QTextEdit* source, QWidget* parent = 0);
~Logger();
public slots:
void log(QString message);
private:
QTextEdit* LoggerEdit;
QTextEdit* texteditSource;
void showMessage(QString message);
};
#endif // LOGGER_H
Logger cpp
#include "logger.h"
Logger::Logger(QTextEdit* source, QWidget* parent):
QDockWidget(parent),texteditSource(source)
{
QDockWidget::setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
LoggerEdit = new QTextEdit();
LoggerEdit->setReadOnly(true);
QDockWidget::setWidget(LoggerEdit);
}
Logger::~Logger()
{
delete LoggerEdit;
}
void Logger::log(QString message)
{
showMessage(message);
}
void Logger::showMessage(QString message)
{
LoggerEdit->setText(message);
}
Main window widget header
#ifndef CUSTOMMAINWINDOW_H
#define CUSTOMMAINWINDOW_H
#include <QMainWindow>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include "logger.h"
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = 0);
private slots:
void buttonClicked();
private:
QTextEdit* textEdit;
Logger* logger;
QPushButton* button;
};
#endif // CUSTOMMAINWINDOW_H
Main window widget cpp
#include "custommainwindow.h"
MainWindow::MainWindow(QWidget* parent):
QMainWindow(parent)
{
// Set window title
QMainWindow::setWindowTitle("Simple Example");
// Create central text
textEdit = new QTextEdit;// text edit to get text for the docked widget
// Create update button
button = new QPushButton("Update dockable widget");
// Create Logger inherited from QDockWidget
logger = new Logger(textEdit);
QMainWindow::addDockWidget(Qt::RightDockWidgetArea,logger);
// Set central widget
QMainWindow::setCentralWidget(new QWidget);
QMainWindow::centralWidget()->setLayout(new QVBoxLayout);
QMainWindow::centralWidget()->layout()->addWidget(textEdit);
QMainWindow::centralWidget()->layout()->addWidget(button);
// Connect for update docked wiget
QObject::connect(button,SIGNAL(clicked()),this,SLOT(buttonClicked()));
}
void MainWindow::buttonClicked()
{
logger->log(textEdit->toPlainText());
}

Related

How to reimplement resizeevent for QGroupBox in QT and add custom behaviour in it

I have a QMainwindow class, in the cpp file I have certain QGroupBox, I have resize event for the mainwindow when I resize the mainwindow it fires. But I want the resizeevent for the QGroupBox, When I resize the QGroupBox I want to write some custom logic to place a button on the top right corner of the QGroupBpox. I have no idea how to implement the QGroupBox class again and put it into mainwindow so I can write some custom logic in the resize event of QGroupBox.
I tried implementing a class inheriting from QWidget. But this doesnt work.
#ifndef SRIBBLEAREA_H
#define SRIBBLEAREA_H
#include <QGroupBox>
#include <QPushButton>
class ScribbleArea : public QWidget {
Q_OBJECT
public:
ScribbleArea(QWidget* parent = nullptr);
protected:
void resizeEvent(QResizeEvent* event) override;
QGroupBox* sensorBox;
QPushButton* fullScreenButton;
};
#endif
#include <iostream>
#include "ScribbleArea.h"
#include <QtDebug>
ScribbleArea::ScribbleArea(QWidget* parent) : QGroupBox(parent) {
this->setMinimumSize(1, 1);
}
ScribbleArea::~ScribbleArea() {
}
void ScribbleArea::resizeEvent(QResizeEvent* e) {
qDebug() << "resize event called for QGroupBox";
QWidget::resizeEvent(e);
}

How create method for get the child (QWebEngineView) of th curent view tab (QTabWidget)?

I'm trying to make some project with QTabWidget (a litle browser and a text editor with multiple tab like notepad++) but I'm stuck in 2 project when I try to edit a value of widget (QWebEngine or QTextEdit) inside of QTabWidget. This is the code for the litle browser project:
fp.h :
#ifndef FP_H
#define FP_H
#include <QMainWindow>
#include <QWebEngineView>
#include <QWidget>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui { class fp; }
QT_END_NAMESPACE
class fp : public QMainWindow
{
Q_OBJECT
public:
fp(QWidget *parent = nullptr);
~fp();
public slots:
void newtab();
void deltab();
void newpage();
QWebEngineView *ap();
int cui();
private:
Ui::fp *ui;
QWebEngineView *webnav;
};
#endif // FP_H
fp.cpp
#include "fp.h"
#include "ui_fp.h"
fp::fp(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::fp)
{
ui->setupUi(this);
ui->in_url->setText("https://google.com");
}
fp::~fp()
{
delete ui;
}
void fp::newtab()
{
QWebEngineView *webnav = new QWebEngineView;
webnav->load(QUrl("https://google.com"));
webnav->setObjectName("webnav");
ui->in_url->setText("https://google.com");
ui->onglet->addTab(webnav,"Home");
}
int fp::cui()
{
return ui->onglet->currentIndex();
}
QWebEngineView *fp::ap()
{
return ui->onglet->currentWidget()->findChild<QWebEngineView *>("webnav");
}
void fp::deltab()
{
ui->onglet->removeTab(cui());
}
void fp::newpage()
{
QString use_url = ui->in_url->text();
ap()->load(use_url);
}
and there what look like the .ui
Image of .ui in Qdesigner
I try to make work the method "ap" it should return the QWebEngineView child of current viewed tab but when I call the slots "newpage" (it currently using "ap" method) it just crash the application. This slot is trigered when I enter a new URL in the QLineEdit in .ui
(before that I create a new tab whit a QWebEngineView inside whit the slot "newtab" )
void fp::newtab()
{
QWebEngineView *webnav = new QWebEngineView;
webnav->load(QUrl("https://google.com"));
webnav->setObjectName("webnav");
ui->in_url->setText("https://google.com");
ui->onglet->addTab(webnav,"Home");
}
So what wrong whit that line it the good method for get child widget of a QTabWidget? If it the good method what should be modified to make it work?
QWebEngineView *fp::ap()
{
return ui->onglet->currentWidget()->findChild<QWebEngineView *>("webnav");
}
Try something like:
QWebEngineView *view = qobject_cast<QWebEngineView *>(
this->ui->onglet->widget(0)
);
Note to put above somewhere in fp's methods (where you need the reference).
I could use ui->onglet->currentWidget(), but the difference is, that will not work once you have multiple tabs.

Create a new window in Qt which depends on the parent window, but appears outside of the parent window

I want to implement a log for my application, and I want it to be in another window. But of course it should close when the main window is closed.
The main window is created with class Window which inherits from QWidget.
When I create the second window the same way and pass into the constructor "this" as parent, that does not work, everything that is inside new window appears inside parent window. But when I don't pass anything into the constructor of new window, it does not close when the parent window closed.
Try to create the second window which inherits from QDialog.
#ifndef FORM_H
#define FORM_H
#include <QDialog>
namespace Ui {
class Form;
}
class Form : public QDialog
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
~Form();
private slots:
private:
Ui::Form *ui;
};
#endif // FORM_H
And MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include "form.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(showNewWindow()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showNewWindow()
{
Form *form;
form = new Form(this);
form->setModal(false);
form->show();
}
As #hyde commented, you should set Qt::Window for the window flags when you create the window widget, and then you can give it a parent and it will be a "secondary window" and will close when the parent closes. Inheriting from QDialog is fine, but brings along additional baggage that you may not want/need; the simple answer to the question is to use Qt::Window.

QWidget "access violation" exeption

A have a class, inherited from QWidget and Ui_Form (automaticaly generated class, appears when you create a .ui in Qt). It looks like
class MyClass: public QWidget, public Ui_Form {}
Ui_Form has some members, which connected with relevant widgets in the .ui file (for example, QLineEdits, QButtons, etc).
class Ui_Form {
public:
QLineEdit *fileNameEdit;
void setupUi(QWidget *Form) {
fileNameEdit = new QLineEdit(layoutWidget);
fileNameEdit->setObjectName(QStringLiteral("fileNameEdit"));
}
}
As MyClass is inherited from Ui_Form, I can use this membes. But, when I try to do something, I have an exeption "Access violation reading location". For example:
fileNameEdit->setText("String");
Can somebody give an advice?
The way you are incorporating the Ui_Form part is not how Qt proposes it by default. If you look into this button example you can see how the ui part is incorporated diferently:
Header file
#ifndef BUTTON_H
#define BUTTON_H
#include <QWidget>
namespace Ui {
class Button;
}
class Button : public QWidget
{
Q_OBJECT
public:
explicit Button(int n, QWidget *parent = 0);
~Button();
private slots:
void removeRequested();
signals:
void remove(Button* button);
private:
Ui::Button *ui;
};
#endif // BUTTON_H
CPP code
#include "button.h"
#include "ui_button.h"
Button::Button(int n, QWidget *parent) :
QWidget(parent),
ui(new Ui::Button)
{
ui->setupUi(this);
ui->pushButton->setText("Remove button "+QString::number(n));
addAction(ui->actionRemove);
connect(ui->actionRemove,SIGNAL(triggered()),this,SLOT(removeRequested()));
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(removeRequested()));
}
Button::~Button()
{
delete ui;
}
void Button::removeRequested()
{
emit remove(this);
}
The main difference is that I believe you are not calling Ui_From::setupUi function. It is clear to me that you do not need to follow the Qt suggested template (incorporating the ui as a class member rather than inheriting from it), however, it is much clearer from my point of view if you follow the Qt suggestions.

C++ GUI QSpinBox's not showing up

My program compiles and displays my push buttons correctly but for some reason its not displaying the QSpinBox's. I'm pretty new at C++ qt GUI so any input would be greatly appreciated. I also checked if the spinners were being overlapped by the buttons but they were not.
//
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include <QPushButton>
#include <QLabel>
#include <QSpinBox>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void clearx();
void equalsx();
void addx();
void subtractx();
void multiplyx();
void dividex();
void firstnumberx();
void secondnumberx();
private:
QLabel *label;
QPushButton *equal;
QPushButton *clear;
QPushButton *equals;
QPushButton *add;
QPushButton *subtract;
QPushButton *multiply;
QPushButton *divide;
QSpinBox *spinner;
QSpinBox *spinner2;
};
#endif // MAINWINDOW_H
//
// mainwindow.cpp
#include "mainwindow.h"
#include <QTCore/QCoreApplication>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
label = new QLabel("0,this");
label -> setGeometry(QRect(QPoint(75,75),QSize(50,200)));
clear = new QPushButton("Clear", this);
clear -> setGeometry(QRect(QPoint(80,300),QSize(50,50)));
connect(clear,SIGNAL(released()),this,SLOT(clearx()));
equal = new QPushButton("Equal", this);
equal -> setGeometry(QRect(QPoint(110,300),QSize(50,50)));
connect(equal,SIGNAL(released()),this,SLOT(equalx()));
add = new QPushButton("Add", this);
add -> setGeometry(QRect(QPoint(140,300),QSize(50,50)));
connect(add,SIGNAL(released()),this,SLOT(addx()));
subtract = new QPushButton("Subtract", this);
subtract -> setGeometry(QRect(QPoint(170,300),QSize(50,50)));
connect(subtract,SIGNAL(released()),this,SLOT(subtractx()));
multiply = new QPushButton("Multiply", this);
multiply -> setGeometry(QRect(QPoint(200,300),QSize(50,50)));
connect(multiply,SIGNAL(released()),this,SLOT(multiplyx()));
divide = new QPushButton("Divide", this);
divide -> setGeometry(QRect(QPoint(230,300),QSize(50,50)));
connect(divide,SIGNAL(released()),this,SLOT(dividex()));
spinner = new QSpinBox;
spinner -> setGeometry(QRect(QPoint(130,150),QSize(50,50)));
connect(divide,SIGNAL(released()),this,SLOT(firstnumberx()));
spinner->setRange(1,10);
spinner2 = new QSpinBox;
spinner2 -> setGeometry(QRect(QPoint(190,150),QSize(50,50)));
connect(divide,SIGNAL(released()),this,SLOT(secondnumberx()));
spinner2->setRange(1,10);
}
void MainWindow::clearx() {}
void MainWindow::equalsx() {}
void MainWindow::addx() {}
void MainWindow::subtractx() {}
void MainWindow::multiplyx() {}
void MainWindow::dividex() {}
void MainWindow::firstnumberx() {}
void MainWindow::secondnumberx() {}
MainWindow::~MainWindow() {}
In order for a widget to display inside another widget, you need to set up a parent-child relationship. The simplest way to do this is to pass a pointer to the parent to the child's constructor as an argument.
For your QSpinBox objects, this is done like so:
spinner = new QSpinBox(this);
spinner2 = new QSpinBox(this);
The rest of your code is very laden with hard-coded geometries. For small GUIs, this might not be a problem but can become a bit of a nightmare to maintain for larger ones. Have you considered using QtDesigner to design your GUI? You might also find the layout management classes helpful in making your GUI designs better maintenance of positions and sizing of child widgets.
Add this as parameter of QSpinBox constructor call.