Embed gnuplot inside existing QtWidget - c++

I am creating a (pseudo) real-time plotting application in C++, using gnuplot as my backend for plotting. One of my requirements is that the plot must be inside an existing window, instead of having a separate plot window (which gnuplot defaults to).
Gnuplot has an option to specify the (Qt) widget ID which seems like this would fit my use case:
set terminal qt widget <id>
I tried passing the value inside my QtWidget::effectiveWinId() to no avail.
Update: Tried using the internal value of the window id QtWidget::winId() with no luck as well.
The problem is that I cannot find any documentation on what <id> is supposed to be. Is this what the developers of gnuplot intended?
Here's an example of my code:
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtNetwork/QLocalSocket>
int main()
{
QApplication app(argc, argv);
QWidget win(nullptr, Qt::Window);
QWidget *window = win.window();
win.show();
std::cout << "effective win id: " << window->effectiveWinId() << "\n";
std::cout << "effective win id: " << win.effectiveWinId() << "\n";
return app.exec();
}
In gnuplot:
gnuplot> set term qt widget <value from effectiveWinId>
gnuplot> plot x
Could not connect to existing qt widget. Starting a new one.

Related

how to translate key shortcut

I cannot force QKeySequence::toString() to return translated shortcut representation despite the fact that it documentation suggests it should work. The docs say: "The strings, "Ctrl", "Shift", etc. are translated using QObject::tr() in the "QShortcut" context." but I am not completely sure what it means by shortcut context. I am probably doing something wrong...
Here is my example. To make it work, I need to copy qtbase_es.qm from Qt installation directory to my project build directory. When the translation is correctly loaded, the action in the menu correctly shows "Action Control+Intro" which is Spanish translation of the shortcut for "Action Ctrl+Enter". But the tooltip on the main window is still "Action (Ctrl+Enter)". I would expect it to be "Action (Control+Intro)", like in the menu. What am I doing wrong?
#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QMainWindow>
#include <QMenuBar>
#include <QTranslator>
int main(int argc, char *argv[])
{
QTranslator spanish;
qDebug() << spanish.load("qtbase_es.qm"); // should return true if correctly loaded
QApplication a(argc, argv);
QApplication::installTranslator(&spanish);
QMainWindow w;
auto menu = new QMenu("Menu");
auto action = menu->addAction("Action");
action->setShortcutContext(Qt::ApplicationShortcut);
action->setShortcut(Qt::CTRL | Qt::Key_Enter);
w.menuBar()->addMenu(menu);
w.show();
QApplication::processEvents(); // I also tried this line but it is useless...
w.setToolTip(QString("%1 (%2)").arg(action->text(), action->shortcut().toString()));
qDebug() << action->shortcut().toString(); // WRONG: returns Ctrl+Enter but I expect Control+Intro
return a.exec();
}
The QShortcut::toString has a SequenceFormat parameter, defaulted to ProtableText. The documentation of the format states, that portable format is intended for e.g. writing to a file.
The native format is intended for displaying to the user, and only this format performs translations.
Try:
qDebug() << action->shortcut().toString(QKeySequence::NativeText);

How to set OffTheRecord profile for QWebEngineView?

How to setup OffTheRecord profile for QWebEngineView?
I use QT5.10 for Linux.
I am going to use it in embedded environment with read-only filesystem and I need to prevent WebEngine writing files and creating folders in filesystem.
#include <QApplication>
#include <QWebEngineView>
#include <QWebEngineSettings>
#include <QWebEngineProfile>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QWebEngineView view;
auto profile = view.page()->profile();
profile->setHttpCacheType(QWebEngineProfile::MemoryHttpCache);
profile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
//profile->setPersistentStoragePath(nullptr);
std::cout << "StoragePath: " << profile->persistentStoragePath().toStdString() << std::endl;
std::cout << "isOffTheRecord: " << profile->isOffTheRecord() << std::endl;
profile->settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true); // Since Qt5.7
profile->settings()->setAttribute(QWebEngineSettings::XSSAuditingEnabled, false);
view.setUrl(QUrl(QStringLiteral("http://localhost/index.html")));
view.resize(1920, 1080);
view.show();
return a.exec();
}
Try this configuration:
First of all, disable any possible cookie. Use setPersistentCookiesPolicy and set it to NoPersistentCookies
If you can write in to a given folder, try to save all temporal files in a secure storage:
auto *profile = QWebEngineProfile::defaultProfile();
profile->setCachePath("yourfolder");
profile->setPersistentStoragePath("yourfolder");
This should give you the control of all the temporal files that are generated by the Web Engine.
If not, taking a look in to Qt repo, you can see that the variable that manage this state is controlled in BrowserContextAdapter, this variable is set up to false, if the storage path is empty while creating the browser context.
So if you create your own QWebEngineProfile with an empty QString as path and use it as default profile:
QWebEngineProfile* profile = new QWebEngineProfile(QString(), parent)
std::cout << "isOffTheRecord: " << profile->isOffTheRecord() << std::endl; // Should return true
This can be done easily if you use it to create any single QWebEnginePage manually using this profile and set it in your QWebEngineView using setPage:
engineview->setPage(new QWebEnginePage(profile, parent));
The documentation for QWebEngineProfile's default constructor states:
Constructs a new off-the-record profile with the parent parent.
An off-the-record profile leaves no record on the local machine, and
has no persistent data or cache. Thus, the HTTP cache can only be in
memory and the cookies can only be non-persistent. Trying to change
these settings will have no effect.
Once you've created a default QWebEngineProfile, pass it to a QWebEnginePage and set that as the page in your QWebEngineView.
Here's a simple example that compiles and runs (tested on Mac OS):
#include <QApplication>
#include <QWebEngineView>
#include <QWebEngineSettings>
#include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWebEngineView view;
QWebEngineProfile profile;
QWebEnginePage page(&profile);
qDebug() << "StoragePath:" << profile.persistentStoragePath();
qDebug() << "isOffTheRecord:" << profile.isOffTheRecord();
view.setPage(&page);
view.setUrl(QUrl(QStringLiteral("http://www.stackoverflow.com/")));
view.show();
return a.exec();
}
When running the above you should see this appear in standard out:
StoragePath: ""
isOffTheRecord: true

QCompleter::activated disconnected after losing and gaining focus

I found a strange case which I do not understand. Maybe it is a Qt bug, maybe I am doing something wrong.
A header:
// File mylineedit.h
#pragma once
#include <QLineEdit>
#include <QDebug>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) { }
public slots:
void onCompleterActivated(const QString& text) { qDebug() << "MyLineEdit" << text; }
};
And the main source file:
// File main.cpp
#include <QApplication>
#include <QWidget>
#include <QStringListModel>
#include <QCompleter>
#include <QVBoxLayout>
#include "mylineedit.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QLineEdit* lineEdit1 = new MyLineEdit();
QLineEdit* lineEdit2 = new MyLineEdit();
auto layout = new QVBoxLayout(&w);
layout->addWidget(lineEdit1);
layout->addWidget(lineEdit2);
lineEdit1->setCompleter(new QCompleter());
auto model = new QStringListModel(QStringList() << "A" << "B" << "C");
lineEdit1->completer()->setModel(model);
QObject::connect(lineEdit1->completer(), SIGNAL(activated(QString)), lineEdit1, SLOT(onCompleterActivated(QString)));
w.show();
return a.exec();
}
Once you run this, you can get a completer with values "A", "B", "C" in the first line edit. When you select any of these values, it will print the message to the console. This is correct. But then change focus to the other line edit and then back. Try picking "A", "B", "C" again. No message is printed out, the signal/slot seems disconnected. Any ideas?
Tested with MinGW 5.3.0 and MSVC 2015 using with Qt 5.9.2.
I modified your sample slightly and tried to reproduce the behavior you described but I couldn't:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version: " << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
QWidget qWin;
QVBoxLayout qVBox;
QLineEdit qEdit1;
qVBox.addWidget(&qEdit1);
QCompleter qCompl1;
QStringListModel qComplModel(QStringList() << "A" << "B" << "C");
qCompl1.setModel(&qComplModel);
qEdit1.setCompleter(&qCompl1);
QLineEdit qEdit2;
qVBox.addWidget(&qEdit2);
qWin.setLayout(&qVBox);
qWin.show();
// install signal handlers
QObject::connect(&qCompl1,
static_cast<void(QCompleter::*)(const QString&)>(
&QCompleter::activated),
[](const QString &text)
{
qDebug() << "Activated: " << text;
});
// run-time loop
return app.exec();
}
The significant differences in my sample:
I used Qt5 style signal handlers (as I'm used to).
I didn't new the Qt widgets (as I'm used to when I write minimal samples).
For me, it's hard to believe that one of these changes makes your described issue unbroken.
I compiled and tested with VS2013, Qt 5.9.2 on Windows 10 (64 bit):
I did the following interactions:
click in qEdit1
type A and click on item A in the popup menu
Output:
Activated: "A"
I continued with:
click in qEdit2
type B
click in qEdit1
erase text, type B, and click on item B in the popup menu
Output:
Activated: "B"
It works like expected.
After some conversation, I had a look at woboq.org in the source code of QLineEdit:
The interesting part is in QLineEdit::focusOutEvent:
if (d->control->completer()) {
QObject::disconnect(d->control->completer(), 0, this, 0);
}
If I read this right, all signal handlers of QLineEdit (emitted by the set completer) are disconnected. I believe this is the reason for the observed issue. (Therefore, it works for lambdas and methods of other classes.)

Qt: Getting the current application palette

I have a class that composes a palette and assigns it to the application using QApplication::instance()->setPalette(QPalette palette).
And it effectively works.
But then I try to use QPalette QApplication::instance()->palette() to extract some colours.
But here it does not work, it just returns the default palette, not the current one.
After I have discovered that it is working as supposed and described in the documentation.
And now I have just 2 questions:
Why it is working in such a strange, useless and counter-intuitive
mode?
How I can retrieve the palette which was set using
QApplication::instance()->setPalette(QPalette palette)?
P.S. No, I can't keep that palette elsewhere.
I think it is an issue of your Qt version (you marked the question as Qt 5 but didn't indicate a specific version), or you have something else in your project that is resetting the palette (you mentioned it has a large code base).
This minimum example shows correct behavior, at least with Qt 5.12.3 32bits, Windows, VS 2017:
#include <QApplication>
#include <QPalette>
#include <QDebug>
#include <QTimer>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
const auto group = QPalette::Active;
const auto role = QPalette::Text;
auto palette = QApplication::palette();
qDebug() << "palette before:" << palette.color(group, role).name();
palette.setColor(group, role, "#123456");
qDebug() << "palette set:" << palette.color(group, role).name();
QApplication::setPalette(palette);
const auto palette2 = QApplication::palette();
qDebug() << "palette after:" << palette2.color(group, role).name();
QTimer::singleShot(100, [=]() { // check palette after the events loop has started
const auto palette3 = QApplication::palette();
qDebug() << "palette after 100ms:" << palette3.color(group, role).name();
});
QWidget w;
w.show();
return a.exec();
}
I've used QApplication::palette my self to retrieve custom palettes in different projects and had no issues at all.
QGuiApplication::setPalette is documented to change the default palette, so basically I think default palette means the palette used if a widget doesn't specify the other one; not the default system palette.
PS: I couldn't make it compile when using QApplication::instance()->setPalette since QApplication doesn't defines instance() but it falls to QCoreApplication::instance(), which obviously returns a QCoreApplication. Probably just a typo when you wrote the question, but I thought it deserved some lines. Given that the palette related methods are static, I decided to use those in the example, but I had the same results using the singleton from qApp.

c++ gui button output

i have a few questions regarding the gui of cplusplus using Qt creator
well i output an array using a forloop when user's choice is for example "1"
so in qt i created a button for that and i linked it with another window
so when i press on the button it opens another window
now i want to add the output of the forloop into this window
should i include iostream in the new window's .cpp file?
or what should i enter exactly?
in the mainwindow.cpp file here is the code i used to open a new window
void MainWindow::on_pushButton_clicked()
{
movies movies;
movies.setModal(true);
movies.exec();
}
thanks.
You should add a QTextEdit to your window (can be done via Qdesigner). And give this object a name e.g. Textout. Then in the code you should get a pointer to this object through your ui object. And you can use one of many methods to set the text of this object. setText is one option
ui->Textout->setText(Your_output_as_qstring)
Your can use QTextStream to format your text if necessary. Formating can be done with QString as well.
example:
#include <sstream>
#include <QLabel>
#include <QApplication>
int main(int argc, char *argv[])
{
std::stringstream ss;
for (auto s: {"first line", "second line"})
ss << s << std::endl;
QApplication a(argc, argv);
QLabel l;
l.setText(ss.str().c_str());
l.show();
return a.exec();
}