I'm writing a QT application that includes QTextBrowser.
When the app doing some functions the function prints lines in the QTextBrowser and during write the lines if i press the mouse left button on any printed line on the QTextBrowser the app restart printing the lines from that line i pressed on.
how to prevent that ?
Example:
all function output:
Device user: xvalid 1
Device model: alpha 16
Device name: Samsoni
Working stage: level 16
during the lines printing if i press on second line with left mouse button this will happen:
Device user: xvalid 1
Device model: alpha 16 Device name: Samsoni
Working stage: level 16
as you see the app will re-set the start writing point from where i pressed
The docs indicates that when you use insertHtml() it is similar to:
edit->textCursor().insertHtml(fragment);
That is, the HTML is added where the cursor is and when you press with the mouse the cursor moves to the position where you click.
The solution is to move the cursor to the end:
QTextCursor cursor = your_QTextBrowser->textCursor(); // get current cursor
cursor.movePosition(QTextCursor::End); // move it to the end of the document
cursor.insertHtml(text); // insert HTML
Example:
#include <QApplication>
#include <QTextBrowser>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextBrowser w;
int counter = 0;
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&w, &counter](){
QString text = QString::number(counter);
// at html
QTextCursor cursor = w.textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertHtml(text);
counter++;
});
timer.start(1000);
w.show();
return a.exec();
}
Related
i am making a Tail Log application. It is executing perfectly but the output window is not showing any results.
Below is the code:
LogTail.cpp
#include "logtail.h"
#include <QApplication>
#include <QTextEdit>
#include<QDebug>
//start id=constructor
LogTail::LogTail(QString fn) {
//if (fn == QString()) {
// fn = "C:/Users/arpit.k/OneDrive - Accord Software & Systems Pvt. Ltd/Documents/QT/LogTail3/sample.log";
// }
connect (this, SIGNAL(readyReadStandardOutput()),
this, SLOT(logOutput())); /* When there is input ready, call this slot.*/
QStringList argv;
argv << "-f" << fn; /* tail -f filename */
start("tail", argv); /* Returns immediately, and now there is a child process running, "attached"
to this process. When this process exits, the child tail process will also terminate. */
}
LogTail::~LogTail() {
terminate(); /* Attempts to terminate this process. */
}
//end
//start id=logOutput
// tail sends its output to stdout.
void LogTail::logOutput() { /* Slot called whenever there is input to read. */
QByteArray bytes = readAllStandardOutput();
QStringList lines = QString(bytes).split("\n");
foreach (QString line, lines) {
//qDebug() << line;
emit logString(line);
}
}
//end
main.cpp
#include "logtail.h"
#include <QTextEdit>
#include <QApplication>
int main (int argc, char* argv[]) {
QApplication app(argc, argv);
QStringList al = app.arguments();
QTextEdit textEdit;
textEdit.setWindowTitle("Debug");
textEdit.setWindowTitle("logtail demo");
QString filename = "sample.log";
if (al.size() > 1) filename = al[1];
LogTail tail(filename); /* Create object, starts process too. */
tail.connect (&tail, SIGNAL(logString(const QString&)),
&textEdit, SLOT(append(const QString&)));
textEdit.show();
return app.exec();
}
Note: sample.log file contains some log data
Output window doesn't show any logs:
(https://i.stack.imgur.com/ENhqs.png)
I need it to display recent 10 Log lines!
Assuming you are subclassing from QProcess (you should post a complete minimal example in order to get an accurate answer).
You are starting the process in the constructor of LogTail, 'tail' will probably output some data or some events that will trigger readyReadStandardOutput before you have the chance to connect the signal in the main function.
readyReadStandardOutput will be triggered only once as you never cleared the input buffer (you never had the chance to read the available data).
So in order to make your example work you should call logOutput after you start the process.
Anyway I will suggest you to implement differently, I would call start from outside or at least outside the constructor, that way your object will be more scalable.
I have two separate c++ projects that run simultaneously and exchange information between them using TCP/IP.
The names of those two projects are "World" and "Platform". To display Data and output in Real time, I have created a Qapplication object inside "World" class.
(I do not want to use Qt forms to create QGprahics view I just want to code it). TCP/IP works without any problems.
here is my code:
main.cpp:
#include "QTcpServer"
#include "QTcpSocket"
#include "QApplication"
#include "QGraphicsScene"
#include "QTime"
World::World()
{
WorldSettings settings;
Sys = new Dynamics(settings);
}
void World::run()
{
while (!time->finished())
{
if (controlStatus)
{
sendWorldData();
getPlatformData();
}
displayData();
}
int World::displayData()
{ char *argv[] = {"a", "arg1", "arg2", NULL};
int argc = sizeof(argv) / sizeof(char*) - 1;
QApplication a(argc, argv);
QGraphicsScene * scene = new QGraphicsScene();
// create an item to put into the scene
QGraphicsRectItem * sag = new QGraphicsRectItem();
sag->setRect(0,0,10,15);
view->show();
return a.exec();
}
with run this file, in first step time, the widget viwe is display and then the program stops running.(In other words, the program stops in the first iteration).
I expect the code I'm writing to behave like this:First, the widget is displayed and then the data are displayed in the corresponding graphic items, number displays, etc. and in every iteration of the code, these display objects are updated. In other words, I have a real time program that I need to display it's output data in real time.
My class names is like (what it does)_(type) for example: reg_QDialog
Here is code of an executing dlg and if Accepted creating QMainWindow:
if(log_dlg->exec() == QDialog::Accepted)
{
find_wnd = new find_QMainWindow();
find_wnd->show();
}
log_dlg has 2 btns: "Enter" (here is the accept result) and "Reg" (opens a new dlg)
"Enter" and "Reg" code is here:
void log_QDialog::on_btn_enter_clicked()
{
this->accept();
}
void log_QDialog::on_btn_reg_clicked()
{
reg_QDialog *reg_dlg = new reg_QDialog();
this->hide();
if(reg_wnd->exec() == QDialog::Accepted)
{
//code
}
this->show();
}
So, here is the problem:
Step by step:
1) run the prog //it starts with dlg_log
2) "Reg" //creating dlg_reg
3) accept dlg_reg //returning to dlg_log
4) "Enter" //trying to create QMainWindow
QMainWindow is not created, and the app just closed
After "returning"(it's, actually, just hiding and then showing) from the reg_dlg and pushing btn with accept result it does nothing! It just closes the programm, but it had to show QMainWindow!
All real code of main.cpp:
#include "log_window_root.h"
#include "find_mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
log_window_root * log_wnd;
find_mainwindow * find_wnd;
log_wnd = new log_window_root();
log_wnd->setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
log_wnd->setModal(true);
if(log_wnd->exec() == QDialog::Accepted)
{
find_wnd = new find_mainwindow();
find_wnd->setWindowFlags(Qt::MSWindowsFixedSizeDialogHint);
find_wnd->show();
}
return a.exec();
}
You are a operating a bit beyond the limits of Qt. Looking at the documentation:
Generally, no user interaction can take place before calling exec().
As a special case, modal widgets like QMessageBox can be used before
calling exec(), because modal widgets call exec() to start a local
event loop.
Testing your code on Mac OS will give you the dreaded warning
modalSession has been exited prematurely - check for a reentrant call
to endModalSession
which shows, that you are working on thin ice and your code will break any time.
Consider reworking your code so that the MainWindow comes up and then show your dialogs. If you want to go on with the Dialog sequence, then remove the hide()/show() pair from on_btn_reg_clicked (these calls mess up your event loops).
QApplication exits and close when the last window has been closed.
You can discard this by setting QApplication::quitOnLastWindowClosed property to false.
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
You may want to revert it to it's previous state when your job is done with those dialogs.
As #Jens mentioned in the other answer to your question, this is will break evenloop at some point and QApplication exits before even a.exec() being called. So, you can also create a zero width/height or off-screen QWidget as a parent of your dialogs. A QSplashScreen is also a good candidate for this. All your dialogs should be your splash screen children. At last, you can finish your splash screen by calling QSplashScreen::finish.
[Re-posting from duplicate-closed question since the top banner on it may cause people to skip that question entirely, and IMHO this one doesn't have a good answer.]
Here's a very simple example of showing a dialog before a QMainWindow. The dialog simply presents the option of starting the main app or not. They key points are that the QDialog portion happens before any other widgets are created (eg. QMainWindow here), and the app (main()) exits before that if needed. No reason to keep the QDialog around after it is used, so I create it on the stack and delete afterwards.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog *d = new QDialog();
QPushButton *pbYes = new QPushButton("Would you like to play a game?", d);
QPushButton *pbNo = new QPushButton("Get me out of here!", d);
QObject::connect(pbYes, &QPushButton::clicked, [d]() { d->done(QDialog::Accepted); });
QObject::connect(pbNo, &QPushButton::clicked, [d]() { d->done(QDialog::Rejected); });
d->setLayout(new QVBoxLayout);
d->layout()->addWidget(pbYes);
d->layout()->addWidget(pbNo);
const int ret = d->exec();
delete d;
if (ret == QDialog::Rejected)
return 0;
QMainWindow mw;
mw.setCentralWidget(new QLabel("Welcome to the Game!", &mw));
mw.show();
return a.exec();
}
Am trying to print "Some text" to QTextBrowser, continuously for "n" time. Where "n" is integer. For this I have used QTimer::SingleShot for timing. Once the timeout is triggered a FLAG is set to false and this "FLAG" is monitored in while loop to break when FLAG is false and it shall insert the text till FLAG is set to FALSE. Initial value for FLAG is true.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
FLAG = true;
}
void MainWindow::on_pushButton_clicked()
{
ui->pushButton->setEnabled(false);
RunTheTimer();
int counter = 0;
do
{
ui->textBrowser->insertPlainText(QString("Inside While loop %1 \n").arg(counter++));
counter++;
}while(FLAG);
FLAG = true;
}
void MainWindow::RunTheTimer()
{
ui->textBrowser-> insertPlainText("Timer Started");
QTimer::singleShot(60000, this, SLOT(Update()));// One Minute
}
void MainWindow::Update()
{
ui->textBrowser-> insertPlainText("Timeout signal triggered");
ui->pushButton->setEnabled(true);
FLAG = false;
}
MainWindow::~MainWindow()
{
delete ui;
}
Application is getting Hang, When I click Pushbutton.
After debugging I observed, timeout is not triggering once the execution is entered to while(1) loop and application is not able to insert any text inside while(1) loop. Why this behavior? What am I doing wrong?
Thanks.
You are not returning control to the event loop, many things in Qt are not designed to work without an event loop, Have a look at this page from the Qt wiki, in your case:
QTextBrowser won't be able to show the newly added text, since this requires the widget to be able to receive paint events (and this is impossible without an event loop).
The timer that sets your flag to false won't be able to fire, since your program is always busy executing your while loop, and it won't be able to do anything else (unless it gets out from that while loop and this is impossible if it does not set your flag to false. . .).
Instead of using an endless loop, if you want to execute something as repeatedly as possible, you can use a QTimer and set its interval property to 0, this is a special value that causes the timer to timeout as soon as the event loop finishes processing all events in the event queue.
Using the above approach instead of your endless loop, you can use another timer to stop the above timer after a specific amount of time, and you don't have to worry about events not arriving and timers not firing since the event loop is always executing now.
Here is a possible implementation of the above approach:
#include <QtWidgets>
int main(int argc, char* argv[]){
QApplication a(argc, argv);
//set up GUI
QWidget widget;
QVBoxLayout layout(&widget);
QTextBrowser textBrowser;
QPushButton button("Add Text");
layout.addWidget(&textBrowser);
layout.addWidget(&button);
//timer with 0 interval instead of while loop
QTimer workTimer;
workTimer.setInterval(0);
int counter=0;
QObject::connect(&workTimer, &QTimer::timeout, [&]{
//add text to textBrowser whenever the workTimer fires
textBrowser.append(QStringLiteral("Additional Text %1").arg(counter++));
});
//when the button is clicked
QObject::connect(&button, &QPushButton::clicked, [&]{
//start work timer
workTimer.start();
button.setEnabled(false);
//stop work timer after 5 seconds
QTimer::singleShot(5000, [&]{
workTimer.stop();
button.setEnabled(true);
});
});
widget.show();
return a.exec();
}
I'm making an application for Mac OS X in Qt, and wanted to spawn a thread that doesn't close on application close.
Is this possible? If so, how? I don't want the process to be stopped if a user force quits the application.
Thanks in advance.
Note: If this is not possible, is there any way I can make this happen? (Maybe with calling a command in bash?)
it's possible to achieve your goal by initiating a new process via QProcess::startDetached, as per documents http://doc.qt.io/qt-4.8/qprocess.html#startDetached
Starts the program program with the arguments arguments in a new process, and detaches from it. Returns true on success; otherwise returns false. If the calling process exits, the detached process will continue to live.
Unix: The started process will run in its own session and act like a daemon.
Edit:
Here is an example for MacOS
// run start script
QString scriptPath = "path-to-start-script/start.sh" ;
QString cmd = "open -a " + scriptPath;
QProcess::startDetached(cmd);
When you terminate a process, all threads within that process die - the process is the thread "container". If you want to spawn something that lives on beyond your current process, then spawn a new independant process.
If your user force-quits the application, that usually means that they want to control the energy or resource expenditure on their system. Thinking that you know better than the user would be rather in the user's face. Don't anger your users :)
All you really want is:
For the process to survive quitting it through normal means (pressing ⌘-Q, selecting Quit from the menu, closing the last window, etc.).
For the dock icon to disappear after the GUI has been quit, as is the normal and expected behavior.
For a cleanup code to run after the GUI has vanished.
To that effect, you only need to hide the dock icon/menubar and then perform the cleanup:
main.mm
// https://github.com/KubaO/stackoverflown/tree/master/questions/hidedock-39378276
#include <QtWidgets>
#include <AppKit/AppKit.h>
void hideDockIcon() {
[NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited];
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QLabel label{"Quit Me"};
label.setMinimumSize(200, 100);
label.show();
int rc = app.exec();
hideDockIcon();
qDebug() << "cleaning up";
QThread::sleep(5);
qDebug() << "cleanup finished";
return rc;
}
hidedock-39378276.pro
QT = widgets
CONFIG += c++11
TARGET = hidedock-39378276
TEMPLATE = app
OBJECTIVE_SOURCES += main.mm
LIBS += -framework AppKit
If u mean closing of Gui window by "Application Close" then it can be done easily...
#include "MainWindow.h"
#include <QApplication>
//////////////////////////////////////
#include <thread>
struct blabla {
std::thread th;
blabla():th([]{
// body of your thread
}) {}
~blabla(){
if(th.joinable())
th.join();
}
} singleton_obj;
/////////////////////////////////////
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Now the applicaton window will quit but the daemon thread will run n background...
Enjoy