Resizing web page inside a spliter in qt - c++

My question is simple, but I have been struggling to find the solution. I have the QMainWindow showed in the image, constructed in the QtCreator.
I want to load an html web page in the QWidget csWindow, for that I have placed a Qlabel label_pic where I load my web Page. This is code so far:
MainWindow::MainWindow(QWidget *parent, Project *project) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->project = project;
QWebEngineView *view = new QWebEngineView(ui->label_pic);
view->load(QUrl("http://localhost/myWeb.html"));
////works fine, for an image
//QPixmap pix(":/img/imgs/someImage.png");
//ui->label_pic->setPixmap(pix);
//I also can load the web page in the QWidget csWindow but with the same result
//QWebEngineView *view = new QWebEngineView(ui->csWindow);
//view->load(QUrl("http://localhost/myWebb.html"));
}
The page loads fine but it does not fit into the corresponding space, It is created with a fixed size and never resize. I want the web page to be resized when I move the spliters, but I have not succed doing it.
I have tried several approaches, first just put an image in label_pic, enable the property scaled contents and works fine. Now, I want to do the same with the web page.
Thanks in advance.

The page loads fine but it does not fit into the corresponding space
This is because the size of the QWebEngineView is not know until it completes loading, so what you need is to connect to its signal loadFinished and resize label_pic :
connect(view, &QWebEngineView::loadFinished, [this]() {this->ui->label_pic->resize(this->ui->csWindow->size());});
I want the web page to be resized when I move the splitters
Then also you need to connect to signal QSplitter::splitterMoved from all your splitters and resize both csWindow and label_pic like this:
connect(ui->splitter, &QSplitter::splitterMoved, [this]() { this->view->resize(this->ui->csWindow->size()); this->ui->label_pic->resize(this->ui->csWindow->size());});
connect(ui->splitter_2, &QSplitter::splitterMoved, [this]() { this->view->resize(this->ui->csWindow->size()); this->ui->label_pic->resize(this->ui->csWindow->size());});
connect(ui->splitter_3, &QSplitter::splitterMoved, [this]() { this->view->resize(this->ui->csWindow->size()); this->ui->label_pic->resize(this->ui->csWindow->size());});
and note that this would work best if you set a layout for your window, either from designer or adding code, for instance:
QGridLayout *layout = new QGridLayout;
layout->addWidget(ui->splitter_3);
this->ui->centralWidget->setLayout(layout);
and remember you should make all connect statements before you load the view.

Related

Qt ignore click when dismissing popup on Windows

I have an issue with Qt where the behavior on Windows is different than Mac or Linux. I discovered the issue on PySide2 but was able to reproduce it in a minimal C++ application as well (see below).
When I dismiss a Popup widget by clicking outside the click is ignored by the rest of the application. This is the desired behavior and is the way it works on Linux and Mac. However in Windows this click is registered by the widget that was clicked which in my application leads to unwanted user input on the underlying widgets.
Is there a way to will prevent the dismissal click from being passed on in Windows? I am fine with having platform dependent code for this issue.
The behavior can be reproduced with this example. When the popup is open and testButton is clicked the onTestButton method will be executed.
#include "mainwindow.h"
#include <QPushButton>
#include <QHBoxLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->setFixedHeight(600);
this->setFixedWidth(800);
QWidget* w = new QWidget();
QDialog* popUp = new QDialog();
popUp->setFixedHeight(200);
popUp->setFixedWidth(200);
popUp->setWindowFlag(Qt::Popup | Qt::FramelessWindowHint);
popUp->setModal(true);
popUp->setVisible(false);
QHBoxLayout *layout = new QHBoxLayout(this);
w->setLayout(layout);
QPushButton* openButton = new QPushButton("open popup");
// same behavior whether using QDialog::show or QDialog::exec
connect(openButton, &QPushButton::clicked, popUp, &QDialog::show);
QPushButton* testButton = new QPushButton("catch mouse");
connect(testButton, &QPushButton::clicked, this, &MainWindow::onTestButton);
layout->addWidget(openButton);
layout->addWidget(testButton);
this->layout()->addWidget(w);
}
void MainWindow::onTestButton()
{
qDebug() << "caught mouse";
}
QWidget is just a widget, if you want it to "hold" focus, then use QDialog instead.
Also it changes the "logic" if u use it as QDialog.show or QDialog.exec.
Can you try with QDialog?
QDialog::setModal(bool) should set the dialog to modal, thus prohibiting clicking into the mainwindow.
Your windowflag Qt::Popup blocked modality. If you want to use that approach and create Qwidget as a modal dialog (Qt::Dialog), it should be launched from another window, or have a parent and used with the QWidget::windowModality property.
Tested:
auto w = new QWidget;
QDialog* popUp = new QDialog;
popUp->setFixedHeight(200);
popUp->setFixedWidth(200);
popUp->setWindowFlags( Qt::FramelessWindowHint);
popUp->setModal(true);
QHBoxLayout *layout = new QHBoxLayout(this);
w->setLayout(layout);

How does one split a QT(C++) UI into multiple widget subclasses and get it to display the same as all in the same class?

I'm learning QT (I already know C++ very well) and trying to get a UI to display well but I do not want to use the QT Designer that comes with QT Creator. I have the following class:
#include "MainPanel.h"
#include<QVBoxLayout>
MainPanel::MainPanel(QWidget *parent)
: QWidget(parent)
{
QLayout *lo = new QVBoxLayout(this);
mList = new QListWidget(this);
mList->addItem("Testing");
setLayout(lo);
lo->addWidget(mList);
lo->setSpacing(5);
}
The Main window class has a bunch of extra protected functions but the initControls method just does this:
void MainWindow::initControls()
{
QHBoxLayout *loMain = new QHBoxLayout(this);
loMain->addWidget(new MainPanel(this));
setLayout(loMain);
}
When I put all the code from MainPanel into MainWindow::initControls() or even in the constructor(either way), it works - shows a list widget with a single item "Testing". With the code in MainPanel though, it shows up as a very small rectangle that wouldn't fit the word "Testing" nor is there any semblance of text in there even partially.
I have tried to override sizeHint() in and move the code to create and return the list widget to a method getList() so I can access it from sizeHint too but that did nothing - I still get a small rectangle.
What am I doing wrong and what do I need to do or include to get the widget to paint properly? I have more controls I want to add to this UI (a button panel below the list widget and a detail panel on the right 2/3 of the window) but until I can get this to display, I can't possibly proceed with the rest.
I also want to do this entirely with code - not using the designer as I have vision issues and found it to be difficult to place things correctly on the form.
Someone please help - documentation and tutorials other than the documentation on QT's website is helpful if it points me to the right direction. I have already looked on QT's docs site under QWidget, QListWidget, QLayout, and QH(and V)BoxLayouts but see nothing and many of the tutorials talk about the designer.
Before someone tries to scold about creating a SSME or whatever small program - I have given you the smallest one that displays the issue - I know that putting the code all into the main window fixes it but one should never have everything in one class.
Okay, too unclear, what's happening there, we should have requested for more of your code =)
Here is the smallest possible sample, demonstrating what you should have been trying to achieve:
mainwindow.cpp:
#include "mainwindow.h"
#include "mainpanel.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
MainPanel* p = new MainPanel(this);
setCentralWidget(p);
}
mainpanel.h:
#include "mainpanel.h"
#include <QListWidget>
#include <QLayout>
MainPanel::MainPanel(QWidget *parent)
: QWidget(parent)
{
QLayout *lo = new QVBoxLayout(this);
QListWidget* mList = new QListWidget(this);
mList->addItem("Testing");
setLayout(lo);
lo->addWidget(mList);
lo->setSpacing(5);
}
main.cpp:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.resize(400, 500);
w.show();
return app.exec();
}
Seemingly, you've tried to set a layout on QMainWindow, but it already has a built-in layout, it is exactly the case when setCentralWidget should work, leave manual layout creation for QWidget & QDialog subclasses.
The code above works fine, try it and refactor the way you want.
#MasterAler is correct that the root cause of your issue is setting a layout MainWindow. The reason for using a MainWindow is to support standard VBoxLayout of menubar, central widget, and status bar. So it makes no sense to set your own layout for a QMainWindow.
Since we didn't have your entire code, I didn't assume MainWindow was a QMainWindow. I got your code to work by making MainWindow a QDialog. This may be more of what you were originally looking for, where you want to put a widget of your own making into any container. Following is in Python (I find Python a faster prototyping environment than C++), but you can easily read it and see how to host your MainPanel is any widget (not just a MainWindow):
import sys
from PySide2.QtWidgets import QApplication, QWidget, QListWidget, QDialog, QVBoxLayout, QHBoxLayout
class MainPanel(QWidget):
def __init__(self, parent):
QWidget.__init__(self, parent)
lo = QVBoxLayout(self)
lo.setSpacing(5)
self.setLayout(lo)
mList = QListWidget(self)
mList.addItem("Testing")
lo.addWidget(mList)
class MainWindow(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
loMain = QHBoxLayout(self)
loMain.addWidget(MainPanel(self))
self.setLayout(loMain)
if __name__ == "__main__":
app = QApplication(sys.argv)
# Show the form
window = MainWindow(None)
window.exec_()

How does work setFeaturePermission member function in QWebEnginePage?

I'm using Qt5.5.0 and wanted to know how does QWebEnginePage::setFeaturePermission work?
In this scenario I wanted to grant the loaded page media audio video capture permission but it does not work:
#include <QtWebEngineWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWebEngineView *view = new QWebEngineView();
view->page()->setUrl(QUrl("http://127.0.0.1:3333/index.html"));
view->page()->setFeaturePermission(view->page()->url(), QWebEnginePage::MediaAudioVideoCapture, QWebEnginePage::PermissionGrantedByUser);
view->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
view->page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
view->show();
return app.exec();
}
What's wrong with my code?
According to the official Qt documentation for QWebEnginePage::setFeaturePermission:
Note: Call this method on featurePermissionRequested() signal, as it
is meant to serve pending feature requests only. Setting feature
permissions ahead of a request has no effect.
So, it has effect only when a feature is requested, for example here is a part of basic Qt Widget Application where QWebEngineView is created in the main window constructor and the signal featurePermissionRequested of the page (QWebEnginePage) is connected to the appropriate slot:
// slot to handle permission request
void MainWindow::featurePermissionRequested(const QUrl & securityOrigin,
QWebEnginePage::Feature feature)
{
// print origin and feature
qDebug() << securityOrigin << feature;
// grant permission
view->page()->setFeaturePermission(view->page()->url(),
QWebEnginePage::MediaAudioCapture, QWebEnginePage::PermissionGrantedByUser);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// store web view pointer as class the member QWebEngineView *view;
view = new QWebEngineView();
// add view widget to 'verticalLayout' added to UI in UI Design
ui->verticalLayout->addWidget(view);
// set view page
view->page()->setUrl(QUrl("https://some_audio_capturing_site"));
// connect page signal with 'this' object slot
connect(view->page(),
SIGNAL(featurePermissionRequested(const QUrl&, QWebEnginePage::Feature)),
SLOT(featurePermissionRequested(const QUrl&, QWebEnginePage::Feature)));
}
I tested this example on one of audio capturing Web sites. When that site requests permission for microphone access it can be seen by debug print that the slot is triggered. It prints the site URL and 2 corresponding to QWebEnginePage::MediaAudioCapture. Nothing happens if the permission is not granted. However, after calling setFeaturePermission in that slot everything works as expected. The Web site is able to capture audio.

How to add tabs dynamically in a Qt?

I want to add tabs dynamically in a Qt application depending on user inputs.
One tab is to be there all the time by default. For convenience, it would be great if I could create the layout and features of this tab in the graphic editor. Then I would like to transfer this layout into code, put in a class constructor and add tabs like:
ui->tabWidget->addTab(new myTabClass(), "Tab 2");
I want to promote this tab programatically as well. Is that possible?
For adding tabs dynamically and constructed by a class, you can use an additional .ui file. This way you can do all the layout stuff with the Qt Designer GUI.
1) Create an empty tab widget in the mainwindow.ui. (eg. named myTabWidget)
2) Add to your project directory a new “Qt Design Form Class” as QWidget class, not as QTabWidget (eg. named MyTabPage):
Right click project -> Add new -> Qt -> Qt Design Form Class
3) In the mytabpage.ui you make the design as you want it to be inserted in myTabWidget.
4) The next step you can instantiate MyTabPage in the MainWindow constructer or elsewhere and add it to myTabWidget. The empty tab in myTabWidget can be removed before. To access paramaters form myNewTab you need a function declared in MyTabPage.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
MyTabPage *myNewTab = new MyTabPage;
ui-> myTabWidget ->removeTab(0);
ui-> myTabWidget ->addTab(myNewTab, tr("name"))
myNewTab->functionDeclaredInMyTabPage (); //access parameters of myNewTab
}
PS: I am aware the question is old. But I want to offer a step by step solution to others cause I had to struggle with it for my self recently.
You can insert tab by int QTabWidget::insertTab ( int index, QWidget * page, const QIcon & icon, const QString & label ) which inserts a tab with the given label, page, and icon into the tab widget at the specified index :
ui->tabWidget->insertTab(1,new myTabClass(),QIcon(QString(":/SomeIcon.ico")),"TabText");
Also removing a tab is done by QTabWidget::removeTab ( int index ).

setCentralWidget() causing the QMainWindow to crash.. Why?

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
this->setupUi(this);
this->setupActions();
this->setWindowTitle(tr("CuteEdit"));
label = new QLabel(tr("No Open Files"));
this->setCentralWidget(label);
label->setAlignment(Qt::AlignCenter);
}
By above code, I get a GUI like this(Its a screenshot of whole screen, Only observe the window displayed in middle of page of ebook). (I used QT Designer)
Now, i want user to select File->Open.. A Dialog appears and file gets selected.. Its contents are to be displayed in *textEdit widget..
Function for that is below..
void MainWindow::loadFile()
{
QString filename = QFileDialog::getOpenFileName(this);
QFile file(filename);
if (file.open(QIODevice::ReadOnly|QIODevice::Text))
{
label->hide();
textEdit->setPlainText(file.readAll());
mFilePath = filename;
QMainWindow::statusBar()->showMessage(tr("File successfully loaded."), 3000);
}
}
The window crashes at line:-
textEdit->setPlainText(file.readAll());
But if i comment the line:-
this->setCentralWidget(label);
i mean i remove label as being the central widget, the program runs as expected.. Why?
And also, I am not clear about the concept of CentralWidget. Pls guide.
JimDaniel is right in his last edit. Take a look at the source code of setCentralWidget():
void QMainWindow::setCentralWidget(QWidget *widget)
{
Q_D(QMainWindow);
if (d->layout->centralWidget() && d->layout->centralWidget() != widget) {
d->layout->centralWidget()->hide();
d->layout->centralWidget()->deleteLater();
}
d->layout->setCentralWidget(widget);
}
Do you see that if your MainWindow already had centralWidget() Qt schedules this object for deletion by deleteLater()?
And centralWidget() is the root widget for all layouts and other widgets in QMainWindow. Not the widget which is centered on window. So each QMainWindow produced by master in Qt Creator already has this root widget. (Take a look at your ui_mainwindow.h as JimDaniel proposed and you will see).
And you schedule this root widget for deletion in your window constructor! Nonsense! =)
I think for you it's a good idea to start new year by reading some book on Qt. =)
Happy New Year!
Are you sure it's not label->hide() that's crashing the app? Perhaps Qt doesn't like you hiding the central widget. I use Qt but I don't mess with QMainWindow that often.
EDIT: I compiled your code. I can help you a bit. Not sure what the ultimate reason is as I don't use the form generator, but you probably shouldn't be resetting the central widget to your label, as it's also set by the designer, if you open the ui_mainwindow.h file and look in setupGui() you can see that it has a widget called centralWidget that's already set. Since you have used the designer for your GUI, I would use it all the way and put the label widget in there as well. That will likely fix your problems. Maybe someone else can be of more help...
I'm not sure I understood your problem, neither what the guys above said (which I guess are valid information) and it seems to be an old topic.
However, I think I had a problem that looks like this and solved it, so I want to contribute my solution in case it helps anyone.
I was trying to "reset" central widget using QLabels. I had three different ones, switch from first to second, then to third and failed to switch back to the first one.
This is my solution that worked:
Header file
QLabel *imageLabel;
Constructor
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Reset
imageLabel = NULL;
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Hope that helps
Aris