Embed a QWebEngineView process inside QTabWidget - c++

I'm trying to integrate a QWebEngineView widget that runs as a separate process(QProcess) inside a QTabWidget page. So far the QWebEngineView process is being started properly but its showing the webpage in a separate window instead of showing it inside the QTabWidget in the MainWindow application.
This is the Widget that is being added to the QTabWidget.
BrokersTerminal.h
class BrokersTerminal : public QWidget
{
Q_OBJECT
public:
explicit BrokersTerminal(QWidget *parent = 0);
~BrokersTerminal();
void startTerminal();
public slots:
void brokersTerminalStarted();
private:
Ui::BrokersTerminal *ui;
QProcess *brokers_process;
QString brokers_program_path;
QStringList arguments;
};
BrokersTerminal.cpp
BrokersTerminal::BrokersTerminal(QWidget *parent) :
QWidget(parent),
ui(new Ui::BrokersTerminal)
{
ui->setupUi(this);
brokers_process = new QProcess( this );
brokers_program_path = QApplication::applicationFilePath();
arguments << "--b";
connect( brokers_process, &QProcess::started, this , &BrokersTerminal::brokersTerminalStarted );
}
BrokersTerminal::~BrokersTerminal()
{
delete ui;
}
void BrokersTerminal::startTerminal()
{
brokers_process->start( brokers_program_path, arguments );
brokers_process->waitForStarted();
}
void BrokersTerminal::brokersTerminalStarted()
{
qDebug() << "Brokers terminal started";
}
This is the WebView Widget that is responsible for displaying the brokers website.
BrokersWebWidget.h
class BrokersWebWidget : public QWidget
{
Q_OBJECT
public:
explicit BrokersWebWidget(QWidget *parent = 0);
~BrokersWebWidget();
private:
Ui::BrokersWebWidget *ui;
QUrl brokers_url;
QWebEngineView *web_browser;
};
BrokersWebWidget.cpp
BrokersWebWidget::BrokersWebWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::BrokersWebWidget)
{
ui->setupUi(this);
brokers_url = "https://siteofbrokersapi.com/";
web_browser = new QWebEngineView( this );
web_browser->load( brokers_url );
}
BrokersWebWidget::~BrokersWebWidget()
{
delete ui;
}
Right now this BrokersWebWidget starts properly as a separate process but it opens in a separate window , but how can this be added in the BrokersTerminal Widget ?
Please let me know of any possible solutions. Thanks.

You cannot embed a widget running in one process into a window run in another. QWidgets can only work with widgets run in the GUI thread in the same process.

Related

Passing a variable from MainWindow to new window

In my MainWindow i have a combobox and a select button. When the select button is clicked a new window is opened.
I want to be able to create a QString variable on the MainWindow that contains the text from the combobox, and pass that QString to the new window. The new window is going to perform different tasks, based on the contents of the QString (based on the selection of the combobox).
The following is my code so far...
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "testwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->cmboTestSelect->addItem("{Please Select a Test}");
ui->cmboTestSelect->addItem("Test 1");
ui->cmboTestSelect->addItem("Test 2");
ui->cmboTestSelect->addItem("Test 3");
ui->cmboTestSelect->addItem("Test 4");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnTestSelect_clicked()
{
QString str_TestSelect = ui->cmboTestSelect->currentText(); //stores "Test Name" in string
hide();
Testwindow = new testwindow(this);
Testwindow->show();
}
The simplest way to do this is, as suggested in the comments, to pass the variable as parameter in the constructor of the class Testwindow. Then you can save the value of the string in a private variable in your Testwindow class and do whatever you want with it.
testwindow.h
class Testwindow : public QMainWindow
{
Q_OBJECT
public:
explicit Testwindow(QString text, QWidget *parent = nullptr);
signals:
private:
QString comboBoxText;
};
testwindow.cpp
Testwindow::Testwindow(QString text, QWidget *parent) : QMainWindow(parent)
{
comboBoxText = text; //now you can use comboBoxText in the rest of Testwindow class
}
mainwindow.cpp
void MainWindow::on_btnTestSelect_clicked()
{
QString str_TestSelect = ui->cmboTestSelect->currentText(); //stores "Test Name" in string
hide();
Testwindow *w = new Testwindow(str_TestSelect, this);
w->show();
}

Qt signal and slots do not work if called from QRunnable or another thread

I am trying to learn how to use Multi-threading in Qt and put it to use in QtWidget applications. So I have setup this simple test case.
MainWindow
This form has some buttons and each button will execute another form (a Dialog for that matter).
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->btnShowCalibrationDialog, &QPushButton::clicked,
this, [&](){
CalibrationDialog dlg;
dlg.exec();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
CalibrationDialog This dialog has a QPushButton and a QTextEdit. When the button is clicked I will run a QRunnable class (comes next!)
calibrationdialog.h (I have spared you the includes and guards!)
class CalibrationDialog : public QDialog
{
Q_OBJECT
public:
explicit CalibrationDialog(QWidget *parent = nullptr);
~CalibrationDialog();
public slots:
void onBeginWorkRequested();
void onReceiveData(int data);
private:
Ui::CalibrationDialog *ui;
};
calibrationdialog.cpp
#include "worker.h"
CalibrationDialog::CalibrationDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::CalibrationDialog)
{
ui->setupUi(this);
connect(ui->btnBegin, &QPushButton::clicked,
this, &CalibrationDialog::onBeginWorkRequested);
}
CalibrationDialog::~CalibrationDialog()
{
delete ui;
}
void CalibrationDialog::onBeginWorkRequested()
{
qDebug() << "CalibrationDialog::onBeginWorkRequested()" << "on" << QThread::currentThreadId();
Worker* worker = new Worker();
QThreadPool* pool = QThreadPool::globalInstance();
connect(worker, &Worker::reportProgress,
this, &CalibrationDialog::onReceiveData);
pool->start(worker);
pool->waitForDone();
}
void CalibrationDialog::onReceiveData(int data)
{
ui->teResults->append(QString::number(data));
ui->teResults->ensureCursorVisible();
}
Worker And this is some runnable...I want to report the progress so that is shows up in the textedit of the dialog in a reponsive manner!
worker.h
class Worker : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
void run() override;
private:
int mProgress = 0;
signals:
void reportProgress(int progress);
};
worker.cpp
Worker::Worker(QObject *parent) : QObject(parent)
{
}
void Worker::run()
{
qDebug() << "Worker is running #" << QThread::currentThreadId();
while(true) {
mProgress += 100;
emit reportProgress(mProgress);
QThread::msleep(500);
}
}
I see in the debugger that control goes in to the while loop...but the signal is not being handled by the dialog! I mean the textedit stays empty!
I tried to read documentationand search online...I came to the conclusion that my problem lies in the waste land of thread affinity....but I have no idea if that is the case and if that is, how to solve it. Please assist!
remove pool->waitForDone();, never use waitForX methods in a GUI since they are blocking preventing signals from doing their job.

QSystemTrayIcon balloon message not showing on El Capitan

I want to display balloon messages with QSystemTrayIcon in my qt app on mac.
The tray icon appears in the right corner of the menu bar of mac. The problem is the balloon message won't show on El Capitan (10.11.6), but it does on Sierra (10.12) and High Sierra (10.13).
The Qt Tray Icon example works just fine on El Capitan though.
QSystemTrayIcon::isSystemTrayAvailable() and QSystemTrayIcon::supportsMessages() both return true.
I don't know what to do anymore. Here's my code:
custom tray icon class (.h)
class MyTrayIcon
{
public:
MyTrayIcon(QObject* parent = nullptr);
~ MyTrayIcon();
void balloonMsg(const QString& title, const QString& message);
QSystemTrayIcon* sysTrayIcon = nullptr;
};
custom tray icon class (.cpp)
MyTrayIcon::MyTrayIcon(QObject* parent)
{
sysTrayIcon = new QSystemTrayIcon(QIcon("my_icon.png"), parent);
}
MyTrayIcon::~MyTrayIcon()
{
delete sysTrayIcon;
}
void MyTrayIcon::balloonMsg(const QString& title, const QString& message)
{
sysTrayIcon->show(); // the icon does show
sysTrayIcon->showMessage(title, message); // the message doesn't show
}
Main window class (.h)
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Ui::MainWindow *ui;
MyTrayIcon* mTrayIcon = nullptr;
public slots:
void btnClicked();
}
Main window class (.cpp)
MainWindow::MainWindow() : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
mTrayIcon = new MyTrayIcon(this);
connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));
}
void MainWindow::btnClicked()
{
mTrayIcon->balloonMsg("my title", "my message");
}
Thanks in advance !

QListWidget cannot add an item dynamically

In my Qt application, I want to add a new item dynamically into a listview. Besides I also used Signal & Slot to transfer data between forms so I have created 2 following forms:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void ReceivedData(QString item);
private slots:
void on_btnAdd_clicked();
void on_btnCancel_clicked();
private:
Ui::MainWindow *ui;
void SetUpListName();
};
addform.h
class AddForm : public QDialog
{
Q_OBJECT
public:
explicit AddForm(QWidget *parent = 0);
~AddForm();
signals:
void SendData(QString item);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::AddForm *ui;
MainWindow *main_window;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
SetUpListName();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::SetUpListName()
{
// Add 5 new elements
for (int i = 0; i < 5; i++) {
QString item = "Item " + QString::number(i);
ui->lwListItem->addItem(item);
}
}
void MainWindow::on_btnAdd_clicked()
{
// Open Add Form
AddForm add;
add.setModal(true);
add.exec();
}
void MainWindow::on_btnCancel_clicked()
{
this->close();
}
void MainWindow::ReceivedData(QString item)
{
// Check to receive data
qDebug() << "Item: " << item;
// Add a new item to list items
ui->lwListItem->addItem(item);
}
addform.cpp
AddForm::AddForm(QWidget *parent) :
QDialog(parent),
ui(new Ui::AddForm)
{
ui->setupUi(this);
main_window = new MainWindow();
connect(this, SIGNAL(SendData(QString)), main_window, SLOT(ReceivedData(QString)));
}
AddForm::~AddForm()
{
delete ui;
}
void AddForm::on_pushButton_clicked()
{
// Send data via Signal & Slot
emit SendData(ui->txtName->text());
}
void AddForm::on_pushButton_2_clicked()
{
this->close();
}
When I run the application, I got the data from Add form but the list view doesn’t add this item.
Does someone have any solutions?
Thanks!
P/S: You can download my source code at here
You are connecting the signal to the wrong object's slot. In the constructor of AddForm, you are creating a new MainWindow and connecting the signal to it's slot which means that the signal does not reach your real MainWindow, and the ReceivedData slot is adding the item to the wrong QListWidget. What you should do is this:
void MainWindow::on_btnAdd_clicked()
{
// Open Add Form
AddForm add;
connect(&add, SIGNAL(SendData(QString)), this, SLOT(ReceivedData(QString)));
add.setModal(true);
add.exec();
}
and remove the creation of a new MainWindow and corresponding connect call from the constructor of AddForm.

Making a borderless window with for Qt

I'm new to Qt C++. I downloaded the latest windows version, did some tutorials and its great.
I saw some styling options that the Qt framework has and its great, but now I need to build my application that its main windows (form) it designed/skinned with image without the rectangle borders (borderless?).
How can I do it with Qt?
If your looking for some advanced styling in the shape of a widget, maybe this example will help you:
Shaped Clock Example
Or maybe you're simply looking for this kind of flag: Qt::CustomizeWindowHint or simply Qt::FramelessWindowHint.
I created a small example, of how to create VS2013 like frameless window in Qt5:
You can get the complete sources here: https://github.com/Jorgen-VikingGod/Qt-Frameless-Window-DarkStyle
Otherwise here a code overview of how to embed the "main" mainwindow into the "frameless" window. Also you can see how to add titlebar, buttons and do maximize, resize and move of the frameless window.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
/*
place your QMainWindow code here
*/
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
/*
this class is to add frameless window supoort and do all the stuff with titlebar and buttons
*/
class BorderlessMainWindow: public QMainWindow
{
Q_OBJECT
public:
explicit BorderlessMainWindow(QWidget *parent = 0);
~BorderlessMainWindow() {}
protected:
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseDoubleClickEvent(QMouseEvent *event);
private slots:
void slot_minimized();
void slot_restored();
void slot_maximized();
void slot_closed();
private:
MainWindow *mMainWindow;
QWidget *mTitlebarWidget;
QLabel *mWindowTitle;
QPushButton *mMinimizeButton;
QPushButton *mRestoreButton;
QPushButton *mMaximizeButton;
QPushButton *mCloseButton;
QPoint mLastMousePosition;
bool mMoving;
bool mMaximized;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
/*
frameless window class: it adds the MainWindow class inside the centralWidget
*/
BorderlessMainWindow::BorderlessMainWindow(QWidget *parent) : QMainWindow(parent, Qt::CustomizeWindowHint ) {
setObjectName("borderlessMainWindow");
setWindowFlags(Qt::FramelessWindowHint| Qt::WindowSystemMenuHint);
// to fix taskbar minimize feature
setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint);
mMainWindow = new MainWindow(this);
setWindowTitle(mMainWindow->windowTitle());
QVBoxLayout *verticalLayout = new QVBoxLayout();
verticalLayout->setSpacing(0);
verticalLayout->setMargin(1);
QHBoxLayout *horizontalLayout = new QHBoxLayout();
horizontalLayout->setSpacing(0);
horizontalLayout->setMargin(0);
mTitlebarWidget = new QWidget(this);
mTitlebarWidget->setObjectName("titlebarWidget");
mTitlebarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
mTitlebarWidget->setLayout(horizontalLayout);
mMinimizeButton = new QPushButton(mTitlebarWidget);
mMinimizeButton->setObjectName("minimizeButton");
connect(mMinimizeButton, SIGNAL(clicked()), this, SLOT(slot_minimized()));
mRestoreButton = new QPushButton(mTitlebarWidget);
mRestoreButton->setObjectName("restoreButton");
mRestoreButton->setVisible(false);
connect(mRestoreButton, SIGNAL(clicked()), this, SLOT(slot_restored()));
mMaximizeButton = new QPushButton(mTitlebarWidget);
mMaximizeButton->setObjectName("maximizeButton");
connect(mMaximizeButton, SIGNAL(clicked()), this, SLOT(slot_maximized()));
mCloseButton = new QPushButton(mTitlebarWidget);
mCloseButton->setObjectName("closeButton");
connect(mCloseButton, SIGNAL(clicked()), this, SLOT(slot_closed()));
mWindowTitle = new QLabel(mTitlebarWidget);
mWindowTitle->setObjectName("windowTitle");
mWindowTitle->setText(windowTitle());
horizontalLayout->addWidget(mWindowTitle);
horizontalLayout->addStretch(1);
horizontalLayout->addWidget(mMinimizeButton);
horizontalLayout->addWidget(mRestoreButton);
horizontalLayout->addWidget(mMaximizeButton);
horizontalLayout->addWidget(mCloseButton);
verticalLayout->addWidget(mTitlebarWidget);
verticalLayout->addWidget(mMainWindow);
QWidget *centralWidget = new QWidget(this);
centralWidget->setObjectName("centralWidget");
centralWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
centralWidget->setLayout(verticalLayout);
setCentralWidget(centralWidget);
}
void BorderlessMainWindow::mousePressEvent(QMouseEvent* event) {
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
if(event->button() == Qt::LeftButton) {
mMoving = true;
mLastMousePosition = event->pos();
}
}
void BorderlessMainWindow::mouseMoveEvent(QMouseEvent* event) {
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
if( event->buttons().testFlag(Qt::LeftButton) && mMoving) {
this->move(this->pos() + (event->pos() - mLastMousePosition));
}
}
void BorderlessMainWindow::mouseReleaseEvent(QMouseEvent* event) {
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
if(event->button() == Qt::LeftButton) {
mMoving = false;
}
}
void BorderlessMainWindow::mouseDoubleClickEvent(QMouseEvent *event) {
Q_UNUSED(event);
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
mMaximized = !mMaximized;
if (mMaximized) {
slot_maximized();
} else {
slot_restored();
}
}
void BorderlessMainWindow::slot_minimized() {
setWindowState(Qt::WindowMinimized);
}
void BorderlessMainWindow::slot_restored() {
mRestoreButton->setVisible(false);
mMaximizeButton->setVisible(true);
setWindowState(Qt::WindowNoState);
setStyleSheet("#borderlessMainWindow{border:1px solid palette(highlight);}");
}
void BorderlessMainWindow::slot_maximized() {
mRestoreButton->setVisible(true);
mMaximizeButton->setVisible(false);
setWindowState(Qt::WindowMaximized);
setStyleSheet("#borderlessMainWindow{border:1px solid palette(base);}");
}
void BorderlessMainWindow::slot_closed() {
close();
}
/*
MainWindow class: put all your code here
*/
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent, Qt::FramelessWindowHint), ui(new Ui::MainWindow) {
ui->setupUi(this);
statusBar()->setSizeGripEnabled(true);
}
MainWindow::~MainWindow() {
delete ui;
}
There is a sample application in your Qt directory: examples/widgets/windowsflags.
I ran into this myself and figured it out after some time. Check out https://github.com/ianbannerman/TrueFramelessWindow for sample code for both Windows & macOS.
Qt::FramelessWindowHint sacrifices resizing and min/max/close, so is probably not what mot people are looking for.