How would you convert the following simple QT example in C using the QWebView widget to Java (QtJambi):
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWebView view;
view.load(QUrl("http://www.trolltech.com/"));
view.show();
return app.exec();
}
(Located at: http://doc.qt.nokia.com/qq/qq26-webplugin.html#qtwebkitbasics)
I could be mistaken but I think I recall such an example being present in the Qt-Jambi javadoc last year, but I can't find it any more, when I go to http://qt-jambi.org/documentation it says "Apidoc of newest built (sic) is not still working"
The API in Qt Jambi is very similar to the original Qt API so the samples can be translated almost directly.
So the C++ version
QWebView view;
view.load(QUrl("http://www.trolltech.com/"));
Is translated to the following in Java
QWebView view = new QWebView();
view.load(new QUrl("http://www.trolltech.com/"));
The rest of the application (creating the main window, running the app) can be found in the hello world tutorial.
I don't have a working environment on my home mac, but this sample should work:
import com.trolltech.qt.core.*;
import com.trolltech.qt.gui.*;
import com.trolltech.qt.webkit.*;
public class SO12093494 extends QMainWindow {
private QWebView webView;
public SO12093494() { this(null); }
public SO12093494(QWidget parent) {
super(parent);
webView = new QWebView();
setCentralWidget(webView);
}
public void loadUrl(String url) {
webView.load(new QUrl(url));
}
public static void main(String[] args) {
QApplication.initialize(args);
SO12093494 app = new SO12093494();
app.loadUrl("http://www.trolltech.com");
app.show();
QApplication.exec();
}
}
Related
I am using Qt5 with new signal/slot syntax.
I don't know why the following code doesn't work:
QWidget *widget = new QWidget();
connect(pipeline, &Pipeline::NewFrame, widget, &QWidget::update);
I get the error:
no matching member function for call to 'connect' why?
Pipeline class inherits from QObject and NewFrame signal has the same signature as QWidget::update
class Pipeline
: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Pipeline)
public:
Pipeline(QObject *parent);
signals:
void NewFrame();
};
I am using QtCreator on Arch Linux with g++.
TL;DR: The pipeline should be signaling an image, and the widget should have a SetImage method:
class Pipeline : public QObject {
Q_OBJECT // important
public:
Q_SIGNAL void NewFrame(const QImage &);
...
};
class Viewer : public QWidget {
Q_OBJECT // important
QImage m_image;
public:
Q_SLOT void SetImage(const QImage &image) {
m_image = image;
update();
}
...
};
This is how you'd be using it - note that Viewer knows nothing about Pipeline, because it shouldn't: it just shows new frames, wherever they come from.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Pipeline pipeline;
Viewer viewer;
QObject::connect(&pipeline, &Pipeline::NewFrame, &viewer, &Viewer::SetImage);
return app.exec();
}
Connecting anything to QWidget::update directly, especially from external sources, is usually a sign of bad design.
To satisfy your curiosity, you can use a lambda or qOverload to specify what you're connecting to, to fix the very error you're seeing - caused by ambiguity of the the type of the method pointer. Any of the following will work:
connect(…, widget, qOverload<>(&QWidget::update));
or
auto constexpr update = qOverload<>(&QWidget::update));
connect(…, widget, update);
or
connect(…, widget, [widget]{ widget->update(); });
My application is designed in that way that different plugins can set the central widget of the main windows to show the desired content.
This works so far.
But if I set a QQuickView-WindowContainer as central widget, the app does not quit when I close the main window.
If I set a "normal" widget like QPushButton as central widget the appliation quits just fine. Why is that?
This is the code of a minimal example which shows this behaviour (MainWindow is a class created from the QtCreator wizard):
class AppCore : public QObject
{
Q_OBJECT
public:
explicit AppCore(QObject *parent = 0);
signals:
public slots:
void showMainWindow();
private:
MainWindow *m_mainWindow;
};
AppCore::AppCore(QObject *parent) :
QObject(parent)
{
}
void AppCore::showMainWindow()
{
QQuickView *view;
QWidget *container;
view = new QQuickView();
container = QWidget::createWindowContainer(view);
view->setSource(QUrl("qrc:/main.qml"));
m_mainWindow = new MainWindow();
//m_mainWindow->setCentralWidget(new QPushButton("Button"));
m_mainWindow->setCentralWidget(container);
m_mainWindow->show();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AppCore appCore;
appCore.showMainWindow();;
return a.exec();
}
This looks like a bug. I see a dead lock in debugger: v8::internal::RuntimeProfiler::WaitForSomeIsolateToEnterJS and QQmlDataLoader::shutdownThread wait for each other. I can't find a good workaround for this issue.
I found a dirty hack that solved the issue. If container is deleted a bit earlier, all works ok:
void MainWindow::closeEvent(QCloseEvent *e) {
QMainWindow::closeEvent(e);
if (e->isAccepted() && centralWidget()) {
delete centralWidget();
}
}
You probably should send a bug report. Note that m_mainWindow is not needed to reproduce the issue. Using container->show(); gives the same result.
This was my original question:
I just want to take a screenshot (using the Print key) of my fullscreen QtQuick 2 application. But all I get is a black or sometimes white screenshot. When the application is not started in fullscreen it works.
SOLUTION
I thought I post a really nice solution here,
even though it does not solve the original problem of taking the screenshot with an external tool.
Starting with the suggestion from the accepted answer I did the following:
First I added a signal to my QML main class (in main.qml)
signal takeScreenShot()
This signal is emmited by pressing a certain button.
Then I wrote a C++ / QT class autside the QML code to handle this signal:
class QMLSupplement : public QObject
{
Q_OBJECT
public:
QQuickView* view;
public:
QMLSupplement(QObject* parent = 0);
public slots:
void takeScreenShot();
};
The reference to QQuickView is used to take the screenshot.
void QMLSupplement::takeScreenShot()
{
QString file;
file = QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss");
file += ".png";
qDebug() << "taking screenshot, saving here:" << file;
view->grabWindow().save(file);
}
Finally I connect the signal and the slot in main.cpp:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl::fromLocalFile("./qml/main.qml"));
view.setResizeMode(QQuickView::SizeRootObjectToView);
QObject* rootObject = (QObject*) view.rootObject();
QMLSupplement supplement;
supplement.view = &view;
QObject::connect(rootObject, SIGNAL(takeScreenShot()),
&supplement, SLOT(takeScreenShot()));
view.show();
// view.showFullScreen();
return app.exec();
}
That's a limitation of the platform where you're running. If you care about this working, you need to implement the functionality yourself. Qt provides you with enough to get the contents of the Qt Quick 2 window and post it to the clipboard as an image.
In your print key handler, if you detect that the window is full-screen, you need to pass the QQuickWindow instance to a helper function:
void grabAndCopy(QQuickWindow * window) {
QApplication::clipboard()->setImage(window->grabWindow());
}
...
if (window->windowState() == Qt::WindowFullScreen) grabAndCopy(window);
I am creating a Qt application and I added dynamic translation (I followed the example at http://www.qtcentre.org/wiki/index.php?title=Dynamic_translation_in_Qt4_applications) with a QCombobox which lists different languages. It works well but the problem is that I don't see how to translate dynamically the text in the dialog windows (for example YES and NO buttons).
In the main.cpp, before executing the app, I have :
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
a.installTranslator(&qtTranslator);
which translate the dialog Windows in the user system language but I would like to do it dynamically like the rest of my app.
Here are the code of the example :
application.h :
#ifndef APPLICATION_H
#include <QApplication>
#include <QHash>
#include <QStringList>
class QDir;
class QTranslator;
typedef QHash<QString, QTranslator*> Translators;
class Application : public QApplication
{
Q_OBJECT
public:
explicit Application(int& argc, char* argv[]);
~Application();
static void loadTranslations(const QString& dir);
static void loadTranslations(const QDir& dir);
static const QStringList availableLanguages();
public slots:
static void setLanguage(const QString& locale);
private:
static QTranslator* current;
static Translators translators;
//static QTranslator* qtTranslator;//test to translate dialog windows
};
#endif // APPLICATION_H
application.cpp :
#include <QDir>
#include <QFileInfo>
#include <QTranslator>
#include <QLibraryInfo>
#include "application.h"
QTranslator* Application::current = 0;
//QTranslator* Application::qtTranslator = 0;//test to translate dialog windows
Translators Application::translators;
Application::Application(int& argc, char* argv[])
: QApplication(argc, argv)
{
}
Application::~Application()
{
}
void Application::loadTranslations(const QString& dir)
{
loadTranslations(QDir(dir));
QString locale = QLocale::system().name().section('_', 0, 0);
QString language=locale+ "_" + locale;
if(!QFile::exists(":Localization/Localization/"+language+".qm"))//if system language is not available, load english version
setLanguage("en_en");
else
setLanguage(language);
}
void Application::loadTranslations(const QDir& dir)
{
// <language>_<country>.qm
QString filter = "*_*.qm";
QDir::Filters filters = QDir::Files | QDir::Readable;
QDir::SortFlags sort = QDir::Name;
QFileInfoList entries = dir.entryInfoList(QStringList() << filter, filters, sort);
foreach (QFileInfo file, entries)
{
// pick country and language out of the file name
QStringList parts = file.baseName().split("_");
QString language = parts.at(parts.count() - 2);
QString country = parts.at(parts.count() - 1);
// construct and load translator
QTranslator* translator = new QTranslator(instance());
if (translator->load(file.absoluteFilePath()))
{
QString locale = language + "_" + country;
translators.insert(locale, translator);
}
}
}
const QStringList Application::availableLanguages()
{
// the content won't get copied thanks to implicit sharing and constness
return QStringList(translators.keys());
}
void Application::setLanguage(const QString& locale)
{
//test to translate dialog windows
/*
QTranslator qtTranslator;
QString qTLocale=locale.mid(0,2);
qtTranslator->load("qt_"+ qTLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
installTranslator(qtTranslator);
//*/
// remove previous
if (current)
{
removeTranslator(current);
}
// install new
current = translators.value(locale, 0);
if (current)
{
installTranslator(current);
}
}
I added the lines commented with "//test to translate dialog Windows" to try the dynamic translation of the dialog Windows but it doesn't work (no error at compilation but the application isn't launched with error message "the program stopped suddenly", I am on Qt Creator). Thanks!
So I finally got this to work after having the same problems. There are two things which were wrong in my case:
Name of the qt translation file:
QTranslator qtTranslator;
qtTranslator.load("qt_de"); // worked in older qt versions
qtTranslator.load("qtbase_de"); // works for qt5.2
a.installTranslator(&qtTranslator);
Have the correct parent for the QMessageBox. This is obvious after you think about it but pretty easy to miss.
QMessageBox::information(someChildOfMainWindow, ...);
For the latter, if you happen to be in a class which is a QObject but not a QWidget you can also use the following code to access your MainWindow from anywhere:
QMainWindow* mw = 0;
foreach(QWidget* widget, QApplication::topLevelWidgets()) {
if(widget->objectName() == "<your-main-window-class-name-here>") {
mw = qobject_cast<QMainWindow>(widget);
}
}
Ok Sébastian Lange, so finally I created the box and didn't use the static ones (
QMessageBox::question(..) for example)
QMessageBox quitMessageBox;
quitMessageBox.setWindowTitle(tr("Quit"));
quitMessageBox.setWindowIcon(QIcon("myIcon.jpg"));
quitMessageBox.setIcon(QMessageBox::Question);
quitMessageBox.setText(tr("Quit the application?"));
quitMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
quitMessageBox.setDefaultButton(QMessageBox::No);
quitMessageBox.button(QMessageBox::Yes)->setText(tr("Yes"));
quitMessageBox.button(QMessageBox::No)->setText(tr("No"));
And then
quitMessageBox.exec();
Like that it's ok. Thanks again!
When providing buttons for the dialog use
tr("Yes")
as for default dialogs, the created .ts-language file (to be edited via QtLinguist) should have default translations included.
The tr() marks the given argument to be translated. This concludes to if you do not know what will be written on a given label, you cannot translate it...
I know similar question to this have been asked, but I haven't found an answer that fixes my problem.
I'm adapting some existing Qt code to add server functionality to a program my company uses. To that end I added a QTcpServer object to the existing dialog, call listen() and connect a slot to the newConnection emitter, like:
.h
class QConsole : public QDialog
{
Q_OBJECT
public:
void init();
public slots:
void new_Connection();
private:
QTcpServer m_Server;
}
.cpp
void QConsole::init()
{
m_Server.listen(QHostAddress::Any, 12346);
QDialog::connect(&m_Server, SIGNAL(newConnection()), this, SLOT(new_Connection()));
}
Main is:
int main( int argc, char *argv[] )
{
QApplication app(argc, argv);
QConsole * _output_window = new QConsole(desktopRect);
_output_window->init();
_output_window->show();
return app.exec();
}
new_Connection() never gets called so I can't see the relevance, but here it is:
void QConsole::new_Connection()
{
}
This works fine in that my program starts listening on the port specified and if I telnet to it a connection of sorts it made, but new_Connection() is never ever ever called!
I've seen posts on this problem dating back to 2005 so it's obviously not a new thing, but what I haven't found is a satisfactory answer to the problem (or any answer actually). This has got everyone at work stumped, even the person that has written a Qt server program. I'm guessing that there is something fundamentally wrong with the existing framework, but I have no idea what it might be.
I have been tearing my hair out for a day and a half over this, and the closes I got to success was using waitForNewConnection() which would actually return me a socket, but when I connected to the readReady() emitter, that was never fired either. So what would prevent these signals never getting called?
Please spare my sanity and help me as much as you can.
Here is a complete working example, tested using MSVC++ 2010.
This listens for a connection on port 12346, replies with "HELLO WORLD" and logs the connection to a list on the dialog.
main.cpp
#include <QtGui>
#include "console.hpp"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Console con;
con.show();
return app.exec();
}
console.hpp
#include <QtCore>
#include <QtGui>
#include <QtNetwork>
class Console : public QDialog
{
Q_OBJECT
public:
Console();
public slots:
void connection();
private:
QTcpServer mServer;
QListWidget* mConnList;
};
console.cpp
#include "console.hpp"
Console::Console() :
QDialog(),
mServer(),
mConnList(new QListWidget())
{
if (!mServer.listen(QHostAddress::Any, 12346))
qDebug() << "Error during 'listen'" << mServer.errorString();
connect(&mServer, SIGNAL(newConnection()), this, SLOT(connection()));
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->addWidget(mConnList);
setLayout(mainLayout);
}
void Console::connection()
{
qDebug() << "CONNECTION";
QTcpSocket* skt = mServer.nextPendingConnection();
if (!skt)
return;
mConnList->addItem(QString("%1:%2").arg(skt->peerAddress().toString()).arg(skt->peerPort()));
skt->write("HELLO WORLD!\r\n");
skt->close();
}
test.pro
TEMPLATE=app
CONFIG+=console debug
QT=core gui network
HEADERS=console.hpp
SOURCES=main.cpp console.cpp
Another working example, again on Linux, although I have coded a program using QTcpServer to run on both Linux and Windows before without a problem. If this doesn't work, surely it must be either a Qt installation or OS configuration problem. Either that or a bug in the Qt version.
~/tcp_test$ qmake --version
QMake version 2.01a
Using Qt version 4.8.6 in /usr/lib/x86_64-linux-gnu
~/tcp_test$ for file in qconsole.{h,cpp} main.cpp tcp_test.pro ; do echo -e "$file:\n"; cat $file; echo; echo; done
qconsole.h:
#include <QDialog>
#include <QTcpServer>
class QConsole : public QDialog
{
Q_OBJECT
public:
QConsole();
public slots:
void connection();
private:
QTcpServer server;
};
qconsole.cpp:
#include "qconsole.h"
QConsole::QConsole()
{
server.listen(QHostAddress::Any, 12346);
QDialog::connect(&server, SIGNAL(newConnection()), this, SLOT(connection()));
}
void QConsole::connection()
{
qDebug("got connection");
}
main.cpp:
#include <QApplication>
#include "qconsole.h"
int main( int argc, char *argv[] )
{
QApplication app(argc, argv);
QConsole * window = new QConsole();
window->show();
return app.exec();
}
tcp_test.pro:
QT = core gui network
CONFIG += debug
TARGET = tcp_test
SOURCES = main.cpp qconsole.cpp
HEADERS = qconsole.h
~/tcp_test$ ./tcp_test &
[3] 9784
~/tcp_test$ nc localhost 12346
got connection
^C