Qt browser app with opengl-es2 strange behaviour (not working) - qt

I have enabled opengl-es2 support in Qt/E and I wanted to make a browser app and the code is :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsView g;
g.setScene(new QGraphicsScene(&g));
g.scene()->setItemIndexMethod(QGraphicsScene::NoIndex);
g.setAttribute(Qt::WA_DeleteOnClose);
g.setOptimizationFlags(QGraphicsView::DontAdjustForAntialiasing);
g.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
g.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
g.setAlignment(Qt::AlignTop | Qt::AlignHCenter);
g.setFrameStyle(QFrame::NoFrame);
g.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
g.setViewport(new QGLWidget());
g.showFullScreen();
QGraphicsWebView view;
view.load(QUrl("http://www.google.com"));
view.setGeometry(QRectF(0,0,800,400));
view.show();
g.scene()->addItem(&view);
a.exec();
}
I can see google page getting loaded for a fraction of second and then after it disappears.
Error log paste-bin link ==> http://pastebin.com/bgbQqd1M

Ashish,
What changes did you make for eglfs platform plug-in?
I also modified eglfs plugin to make it run on an arm board.
Two place that I changed are:
avoid call eglMakeCurrent twice, when EGLDisplay, EGLSurface(Read), EGLSurface(Draw), EGLDisplay not change --- On my board, call eglMakeCurrent twice will cause the program abort.
The problem is same as you (QGLShader::QGLShader: 'context' must be the current context or sharing with it.)
In QtOpengl library, there is a function QGLWidget* qt_gl_share_widget(), that will create a new QGLContext and set it to QPlatformGLContext.
In bool QGLShaderProgram::bind(), it will check the currentContext with the one in QGLSharedResourceGuard. QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext()).
To fix this problem.
I add the following code in qeglplatformcontext.cpp
#include <QGLContext>
class QEGLFSContext : public QGLContext
{
public:
bool chooseContext(const QGLContext* shareContext = 0)
{
QGLContext::chooseContext(shareContext); // in QGLContext, this guy is protected
}
};
void QEGLPlatformContext::makeCurrent()
{
QPlatformGLContext::makeCurrent();
QGLContext * ctx = QGLContext::fromPlatformGLContext(this);
QEGLFSContext* eglctx = (QEGLFSContext*)ctx;
static QEGLFSContext * s_ctx = eglctx;
if (s_ctx != eglctx)
{
s_ctx->chooseContext();
}
//...
}
After use these change, I can run hellogl_es2 and show the animation for show the Qt logo and bubbles well.
But I still have some problem:
QLabel, QMenu... can not show.
Do you have any idea about this problem.
I also got some idea from some guy, qws/simplegl also have these problem.

Related

QMediaPlayer - Playing BGM Continuously in Qt

I am new to Qt. I want to make a game with many different screens (e.g. Main Screen, Loading Screen...), but in a single window, switched by index in a QstackWidget. When switching to the Main Screen, it should play a background music continuously. Searching the web, I found QMediaPlayer with QMediaPlayerlist can do the trick. So I tried like this (using a basic QMainWindow to simplify the code):
QtWidgetApplication1.h
#pragma once
#include <QtWidgets/QMainWindow>
#include <QMediaPlayer>
#include <QMediaPlaylist>
class QtWidgetsApplication1 : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication1(QWidget *parent = Q_NULLPTR);
void playAudio();
void stopAudio();
private:
QMediaPlayer* player;
QMediaPlaylist* playList;
};
QtWidgetApplication1.cpp
#include "QtWidgetsApplication1.h"
QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
: QMainWindow(parent)
{
playAudio();
}
void QtWidgetsApplication1::playAudio() {
player = new QMediaPlayer();
playList = new QMediaPlaylist();
playList->addMedia(QUrl::fromLocalFile("main_theme.mp3"));
playList->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
player->setPlaylist(playList);
player->play();
}
void QtWidgetsApplication1::stopAudio() {
player->stop();
delete player;
delete playList;
player = Q_NULLPTR;
playList = Q_NULLPTR;
}
main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtWidgetsApplication1 w;
w.show();
return a.exec();
}
Error:
It only plays the audio once, and shows an error message
QObject::startTimer: Timers can only be used with threads started with
QThread
Note:
I've tried (1.) using QMediaPlayer only and detecting QMediaPlayer::endOfMedia signal, (2.) QSound with a .wav file. First approach cannot get QMediaPlayer::endOfMedia signal but get QMediaPlayer::pauseState signal, however, I still fail to replay the audio. Second approach doesn't even play the audio and shows a QEventLoop error.
Enviroment:
Windows 10
Qt 5.15.2 MSVC2019 X64
Visual Studio 2019
Instead of adding QT += multimedia in the .pro file, which the projects in VS doesn't have, I tried to include those .lib to the project settings (Refer to How to add Qt libraries to visual studio). Actually, the best way to include QtMultiMedia is: go to
Extensions (in VS) > Qt VS tools > Qt Project Settings > General > Qt Modules and select the modules you want to include. By including the right modules, the problem I have faced has gone.

QSettings persistence constantly writing to config file on initial startup

So I have a qt app running on Linux. When the app is initially launched, QSettings is constantly writing to the settings.conf file even though no changes were made to QSettings. Once a user changes any setting, it stops writing and acts like normal and only writes during changes. Our hardware does not have a power button and so never shuts off and is constantly plugged in so having QSettings constantly writing to the .conf file on start up is a problem.
I looked for timers to make sure no timer was prompting to write and there are none. Tried settings.sync(). I even set a throwaway value on start up, since after changing a value in the app after initial launch it stops writing, but that didn't work. All settings persistence is written this way and after I comment out the settings.setValue at the bottom of the code, the .conf write process works as supposed to. I have no idea why it is writing when values are set from a power button click. Thoughts?
Here is the code and flow:
void MainWindow::onNavBarButtonClicked(int buttonClickedIdAsInt)
{
//.....
case NavBarButton::POWER:
activeScreenContainer->setCurrentWidget(userScreen);
activeScreenContainer ->raise();
navBarFrame->raise();
navBarActiveContainerSeparator->hide();
logoUserScreen->show();
logoUserScreen->raise();
if(orientationSelected == appPersistence::PORTRAIT_ORIENTATION_VALUE) {
timeAndUserFrame->hide();
}
emit userLoggedOut();
}
to
connect(this, &MainWindow::userLoggedOut, musicScreenModel,
&MusicScreenModel::onUserLoggedOut);
to
void MusicScreenModel::onUserLoggedOut()
{
emit userLoggedOutTreble(currentTrebleValue);
}
to
connect(musicScreenModel, &MusicScreenModel::userLoggedOutTreble,
settingsScreenModel, &SettingsScreenModel::onUserLoggedOutTreble);
to
void SettingsScreenModel::onUserLoggedOutTreble(int trebleToStore)
{
settings.setValue(appPersistence::MUSIC_TREBLE_KEY + loggedInUser,
trebleToStore);
}
And main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCoreApplication::setOrganizationName("Organization");
QCoreApplication::setApplicationName("AppName");
QSettings::setPath(QSettings::Format::NativeFormat,QSettings::Scope::UserScope, "/opt/");
QSettings settings;
int fontFamilyId = QFontDatabase::addApplicationFont(":/fonts/Quicksand-Bold.ttf");
settings.setValue(fontStyle::QUICKSAND_BOLD_FAMILY_ID, fontFamilyId);
if(!settings.value(appPersistence::ORIENTATION_SELECTED_KEY).isValid()) {
settings.setValue(appPersistence::ORIENTATION_SELECTED_KEY, appPersistence::LANDSCAPE_ORIENTATION_VALUE);
}
if(true) {
DevOnlyFunctions::seedRng();
}
testBuild::setIsTestBuild(false);
MainWindow w;
w.show();
return a.exec();
}
So I finally figured out what the was going wrong. We have a timer that shows whether certain Can Bus devices are present. If they are not present we hide the icons and log out the user directly through calling the onUserLoggedOut() method and not through a connect statement. I was constantly searching for a timer and connect statement and not a direct method call nested within a switch that uses a timer.

QApplication Within A Shared Library Event Loop Issues

I'm trying to use QWebPage in a shared library, which means I have to have QApplication in there to get a GUI context for it to run in. I've built my code up to get this in place, however as soon as I run qApp->exec() the Event Loop completely blocks and prevents anything else from executing. This is with the shared library being ran on OS X, I've yet to try any other platforms.
I've tried adding a QTimer in to trigger every 100msecs but that doesn't ever get called, I'd assume to the event loop blocking. I've added my QApplication setup code below. I'd assume I either need to run it in a thread, or I've missed something trivial but I'm completely unsure what.
web_lib.cpp
WebLib::WebLib(int argc, char *argv[])
{
QApplication a(argc, argv, false);
connect(&m_eventTimer, SIGNAL(timeout()), this, SLOT(handleEvents()));
m_eventTimer.start(100);
a.exec();
}
void WebLib::renderFile(QString file
{
...some connection code that's boring here
m_page = new QWebPage;
m_page->mainFrame()->load(file);
}
void WebLib::handleEvents()
{
qApp->processEvents()
}
web_lib.h
class WEBLIBSHARED_EXPORT WebLib: public QObject
{
Q_OBJECT
public:
WebLib();
WebLib(int argc, char *argv[]);
void renderFile(QString fileName);
private slots:
void handleEvents();
private:
QWebPage *m_page;
QTimer m_eventTimer;
};
main.cpp
int main(int argc, char *argv[])
{
WebLib *webLib = new webLib(argc, argv);
svgLib->renderFileFromName("somePath");
return 0;
}
As soon as I run qApp->exec() the event loop completely blocks and prevents anything else from executing.
That's correct. After you're done with your rendering, you should exit the event loop.
The timer is useless, since calling processEvents from a nonblocking slot like handleEvents simply forces the event loop to be re-entered for a short time, for no reason.
Your event loop has nothing to do. You need to make the render file request before calling a.exec(), not afterwards. In other words, you need to make the following changes:
In the WebLib constructor:
1. Remove the call to a.exec().
2. Dynamically allocate the QApplication instead of putting it on the stack. 3. Remove the timer, you don't need it.
In web_lib.cpp:
Add WebLib::run(), which will call a.exec().
In main.cpp:
After the call to renderFile(), call webLib->run().
The exec must be run in a tread. Alternatively, you can call QApplication::processEvents periodically.

QFileSystemModel and QTreeView showing dirs only. How to hide expansion marks against the empty dirs?

I'm building somewhat like standard file explorer - left pane is for folders tree, and the right one to display files within selected folder.
QTreeView with QFileSystemModel is used to display folders. Model's filter is set to QDir::Dirs | QDir::NoDotAndDotDot to list dirs only, no files.
I want to display expansion marks only against the folders with subfolders, i. e. if some dir is empty or contains only files, it shouldn't be expandable. But instead, tree view keeps expansion marks against the empty dir. And that's the question: how to hide them?
I've searched the solution here, in the google, in the QT examples - no success. While the question, I think, is very easy to answer.
The only solution I came for at the moment is to subclass QAbstractItemModel. That's pain.
QT 4.8, QT Creator, C++.
Here's code to demonstrate:
#include <QApplication>
#include <QFileSystemModel>
#include <QTreeView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTreeView w;
QFileSystemModel m;
m.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
m.setRootPath("C:\\");
w.setModel(&m);
w.setRootIndex(m.index(m.rootPath()));
w.hideColumn(3);
w.hideColumn(2);
w.hideColumn(1);
w.show();
return a.exec();
}
Simplest way: juste implements hasChildren like that:
/*!
* Returns true if parent has any children and haven't the Qt::ItemNeverHasChildren flag set;
* otherwise returns false.
*
*
* \remarks Reimplemented to avoid empty directories to be collapsables
* and to implement the \c Qt::ItemNeverHasChildren flag.
* \see rowCount()
* \see child()
*
*/
bool YourModelName::hasChildren(const QModelIndex &parent) const
{
// return false if item cant have children
if (parent.flags() & Qt::ItemNeverHasChildren) {
return false;
}
// return if at least one child exists
return QDirIterator(
filePath(parent),
filter() | QDir::NoDotAndDotDot,
QDirIterator::NoIteratorFlags
).hasNext();
}
I have solved this issue using
QFileSystemModel::fetchMore
on each QModelIndex of the current level. To know if a folder has been loaded into the model, you can use the signal
void directoryLoaded ( const QString & path )

how to translate string added dynamicaly in Qapp with Qtranslator?

i trying to created a Qt application multilanguage with Qt linguist.
I place this code in an function of my MainWindow :
translator.load(":/lang/English");
qApp->installTranslator(&translator);
ui->retranslateUi(this);
With the QTranslator declare in my MainWindow.h and all my string i want translate enclose by tr() . But with that, all QObject added dynamicaly by the code of my MainWindow.cpp, for example the title of a QTableWidget, are not translated.
If i place an other translator in my main.cpp, all my string are translate but i must created language button in my application and so i can't place translator in main.cpp.
Do you have an idea to help me?
Thx for your answers.
Gat
When you add a translation in your application using qApp->installTranslator(& aTranslator) then all the following calls to QObject::tr() (and similar functions) will look up in the translator for a translated text. So you should call retranslateUi() after qApp->installTranslator(). Actually you might event not call it there, you may reimplement QWidget::changeEvent() and intercept any QEvent::LanguageChange event.
void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
// Someone called qApp->installTranslator() with a new translation.
// Let's update the user visible strings.
// This function was created by uic from the Designer form.
// It translates all user visible texts in the form.
ui->retranslateUi(this);
// This function must be written by you. It translates other user visible
// texts that are not in the form. See down for an example.
this->retranslateUi();
break;
default:
break;
}
}
ui->retranslateUi() just calls QObject::tr() for each user visible string in the ui. It is called automatically at the end of setupUi() and populates the form's widgets with translated text (have a look, it is defined by uic in ui_MainWindow.h file). You may want to take a similar approach with other user visible texts, like the title of a QTableWidget. All the strings are set in a function (named perhaps retranslateUi() for consistency) which is called at application starts (or, better, after the relevant widgets are created) and every time a new translations is loaded.
MainWindow::MainWindow(QWidget * parent)
: QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Creates other widgets, but do not set their user visible texts.
tableWidget = new QTableWidget(this);
...
someControl = new QLineEdit(this);
someOtherControl = new QSpinBox(this);
someModel = new MyModel(this);
...
// Ok, *now* we set their texts.
this->retranslateUi();
}
...
void MainWindow::retranslateUi()
{
// This function will be called (either manually or automatically by
// `changeEvent()`) when a new translator has installed, hence all the `tr()`
// calls will return the right translation for the last installed language.
QStringList labels;
labels.append(tr("First column"));
labels.append(tr("Second column"));
labels.append(tr("Third column"));
tableWidget->setHorizontalHeaderLabels(labels);
someControl->setText(tr("Control name"));
someOtherControl->setText(tr("Other control name"));
// Perhaps you have a model that need to be retranslated too
// (you need to write its `retranslateUi()` function):
someModel->retranslateUi();
...
}
Also, please note that if you are doing something like
void MainWindow::someFunction()
{
...
QTranslator translator;
translator.load(":/lang/English");
qApp->installTranslator(& translator);
...
}
as soon as that function returns the variable translator gets destroyed, so next time QObject::tr() is called the address stored with qApp->installTranslator(& translator) will be invalid. So you must allocate translator on the heap with new (and possibly deleting it with delete when you do not need it anymore). An exception is if you are doing that in main() before calling QCoreApplication::exec() since that function is blocking and will not return until application is closed.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
...
QTranslator translator;
translator.load(":/lang/English");
app.installTranslator(& translator);
...
app.exec(); // This function will return only on application's exit.
// Hence `translator` will outlive the application, there is
// no need to worry about it.
}

Resources