QTextBrowser could not show all data at run time - c++

My problem is that QTextBrowser can not show all data that is appended to it.
I am using qt5.4 on windows.
My class like this:
class InfoTextBrowser : public QTextBrowser
{
Q_OBJECT
public:
InfoTextBrowser(QObject *parent);
~InfoTextBrowser();
public slots:
void appendText(const QString& text) {
try
{
this->append(text);
}
catch(std::bad_alloc& e)
{
if(!memoryError)
{
QMessageBox::warning(this,"My app", QStringLiteral("Out of Memory"),QMessageBox::Ok);
this->clear();
memoryError = true;
}
}
QScrollBar* myBar = this->verticalScrollBar();
if (myBar!=NULL)
myBar->setValue(myBar->maximum());
};
private:
void contextMenuEvent(QContextMenuEvent *event);
private:
bool memoryError;
};
First I got bad_alloc exception and then I moved my application to 64bit then I do not get any exception. But When I run my program, QTextBrowser stops showing data after a while. It dies and it can not be cleared or refreshed.
I also tried QPlainTextEdit instead of this, but I could not be successful again. I want to show all data at run time or some part of it that could be shown. Because it stops just first paragraph when it dies. In addition, I do not want to show data by reading from a text file.
Is there anyone face with this situation?
Thanks in advance.

Actually, I decided that there is no feasible solution for this, you can not hold this data at run time, It very depends on hardware. You do not have a guarantee to find the needed memory as a whole block.
So I used QPlainTextEdit and restricted to shown text as 100000 blocks by using setMaximumBlockCount(100000)function in the constructor. I appended text with this->appendPlainText(text). Thus,output windows always shows last 100000 block of text. Rest of data can hold a text file or something like that. So user can look all of them from there.

Related

How to display a blinking cursor in QLineEdit during read-only

title pretty much says it all. I have a read-only text box on a form where users can edit the contents of this text box through buttons on the form. The form is basically a keypad. As users click the buttons, a digit will be added to the value in the text box.
Technically, the final application will be running on a machine with no keyboard but a touchscreen. Users interact with the application using the touchscreen and they should not be installing keyboards on the machine but in the event they do, I am making the text box read-only.
Now, how can I have the text box's cursor still blink even though it is read only?
I am wondering if I need to do something similar to this user's solution:
Hide QLineEdit blinking cursor
I have also tried using the setFocus method and I am looking into style sheets. However, nothing has panned out.
Other answers have given you technical solutions to your question. However, I think that you are going in a wrong direction. You want a QLineEdit that is read only, but with a cursor and still accepts input from a virtual keyboard... yeah, so it is not really read only... It is not smelling good.
And in general, arbitrarily and actively disabling standard functions is not a good idea. Especially, if it means hacking your way around standard widget behaviors an semantics to do it.
Let's think from the start. What is the issue of accepting input from a keyboard?
From your question I would dare to guess that you want to make sure that the QLineEdit only accepts digits, and forbid the user to input other characters.
If I am right what you want is a QValidator, either a QIntvalidator or a QRegExpValidator. Then you can let the users use a keyboard, but they will only be able to input digits, like they would with your virtual keyboard.
Create a class whiwh inherits from QLineEdit and ignore the key events (events triggered when the user press a key). It will make your line edit read only but without the look-and-feel:
class LineEdit: public QLineEdit
{
Q_OBJECT
public:
LineEdit(QWidget* parent=nullptr): QLineEdit(parent)
{
}
virtual void keyPressEvent(QKeyEvent* event)
{
event->ignore();
}
public slots:
void add(QString const& textToAdd)
{
setText(text() + textToAdd);
}
};
An usage example (the timer simulates the virtual keyboard):
LineEdit* line = new LineEdit;
line->show();
QTimer timer;
timer.setInterval(2000);
QObject::connect(&timer, &QTimer::timeout, [=]() { line->add("a"); });
timer.start();
Romha Korev's answer will appear to work, but it won't catch everything. It can still be possible to paste or drag&drop text into the line edit, or as a result of a locale dependent input-method keyboard event. I don't know all the various ways text can end up being entered into the line edit that way. You'd be hunting for holes to plug.
So I propose to abuse a QValidator for this. Do not set your line edit to read-only mode. Create your own validator that blocks all input unless you specifically disable it:
class InputBlockerValidator final: public QValidator
{
Q_OBJECT
public:
void enable()
{ is_active_ = true; }
void disable()
{ is_active_ = false; }
QValidator::State validate(QString& /*input*/, int& /*pos*/) const override
{
if (is_active_) {
return QValidator::Invalid;
}
return QValidator::Acceptable;
}
private:
bool is_active_ = true;
};
Now set an instance of this as the validator of your line edit:
// ...
private:
QLineEdit lineedit_;
InputBlockerValidator validator_;
// ...
lineedit_.setValidator(&validator_);
Then, whenever you insert text into the line edit, disable and re-enable the validator:
validator_.disable();
lineedit_.insert(text_to_be_inserted);
validator_.enable();
Do not ever call setText() on the line edit. For some reason, this permanently prevents the validator from blocking input. I don't know if this is intended or a Qt bug. Only use insert(). To simulate setText(), use clear() followed by insert().

QT Model/View like Log Viewer

I have a Monitoring program which runs another long process (can take days). The process generates huge amount of log information. This log information cant be stored in memory so I am redirecting it into log file. The problem is than Monitoring program need to display this log. I cant use a widget that requires storing entire text in memory. I need to have somting like
class TextView
{
void setModel(TextModel*)
}
class TextModel
{
int pageCount();
QString page(int i);
Q_SIGNALS:
void pageCountChanged(int cnt)
};
Implementation of TextModel will load page in memory per request.
Of courese I can implement Text Viewer widget from the scratch, but I have no enough time to do that. Any sugestions?
You can use QListView and derive your model from QAbstractListModel. You need to define rowCount and data methods in your model.

Handling c++ wxWidgets EVT_MAXIMIZE macro

I have a (maybe) simple question. I'd like to resize my program window after the user clicked on "maximize" since I want to fit the data to the window, without leaving "grey patches" (hope it does make sense lol, since I'm from Italy I'm not sure it does) . The problem is if I try to show a simple message, it doesn't show up. This is the piece of code I think you need to look at of my class (cpp file)
void EBCFrame::OnMaximize(wxMaximizeEvent& event)
{
// _window->Fit();
wxMessageBox(_T("maximize test"));
}
// Event table for EBCFrame
BEGIN_EVENT_TABLE(EBCFrame, wxFrame)
...
EVT_MAXIMIZE(EBCFrame::OnMaximize)
END_EVENT_TABLE()
And here's the header file
class EBCFrame : public wxFrame
{
public:
// Constructor
EBCFrame(const wxString& title);
// Event handlers
.....
void OnMaximize(wxMaximizeEvent& event);
private:
// This class handles events
DECLARE_EVENT_TABLE()
wxScrolledWindow* _window;
....
};
I apologize if it's not enough and you need the full code; in that case, I'll provide as soon as I read this question again. Thank you for your support!
Judging from your earlier question's code: wxWidgets: can't inherit from wxListCtrl;
You seem to be using a wxScrolledWindow for a wxListCtrl which is not needed (the wxListCtrl already manages the scrolling of its content) If that is the case, remove the wxScolledWindow from your code.
If that wxListCtrl (EBCList) is the only client window in your frame (EBCFrame), wxWidgets will size it automatically.
If you have added more widgets to your frame in the meantime, you may want to look into the sizer classes to compose your layout (e.g wxBoxSizer).

QPlainTextEdit throwing std::bad_alloc

I have a program that runs a least squares fit to some data. This procedure is run in a separate thread and controlled from a dialog box. This dialog box has a QPlainTextEdit that shows fitting updates and a final report.
The dialog was created in Qt Designer, the code is run into QtCreator and my Qt version is 4.8.1.
The problem I am running into is somewhat erratic. When I run the procedure a first time, everything is fine. Then if I run it again, sometimes the program crashes with the message
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
The program has unexpectedly finished.
I tracked the problem to a call to the clear() method of a QPlainTextEdit. Here is some code.
// Snippets of the class definition
class QLSQDialog : public QDialog, public Ui_QLSQDialog
{
Q_OBJECT
public:
QLSQDialog(QWidget *parent = 0);
(...)
void UpdateDisplay(const QString &msg, int iter, double norm); // Update values of chi, etc on displays
signals:
void Run(); // Signal to run a LSQ procedure
(...)
private slots:
void on_btnRun_clicked();
(...)
private:
void Enables(bool running); // Enable and disable features depending on running state of LSQ fit
(...)
};
// Snippets of the class implementation
QLSQDialog::QLSQDialog(QWidget *parent) : QDialog(parent)
{
setupUi(this); // Set up dialog
(...)
txtInfo->clear(); // txtInfo is a QPlainTextEdit created in Designer
(...)
}
void QLSQDialog::UpdateDisplay(const QString &msg, int iter, double norm)
{
lblChi->setText(QString::number(norm,'f',12));
if (iter >= 0) lblIt->setText(QString::number(iter));
txtInfo->appendPlainText(msg);
}
void QLSQDialog::on_btnRun_clicked()
{
txtInfo->clear(); // Offending line in second run
Enables(true);
emit Run();
}
void QLSQDialog::Enables(bool running)
{
bool Idle = !running;
bool HasReport = !txtInfo->document()->isEmpty();
(...)
btnReport->setEnabled(Idle && HasReport);
}
txtInfo is the QPlainTextEdit object. I call a txtInfo->clear() when the object is
created to show an empty text edit. When I click on a 'Run' tool button its default slot emits a Run signal that will start the new thread. The txtInfo QPlainTextEdit is updated in this thread until it finishes (in fact the thread emits a signal that is caught in the main application that in turn calls the UpdateDisplay).
If I click on the run button a second time, then I get the crash and the error. If I replace txtInfo->clear(), txtInfo->document()->clear(), by txtInfo->setPlainText("") or by txtInfo->document()->setPlainText("") the problem is the same (crash at second execution). Occasionally, but not frequently, I can run a few times (of the order of 10) before crashing.
Finally, if I comment out the txtInfo->clear() line, then I can run the routine as much as I tried (in one test I got tired after running it about 80 times).
My only (almost random) guess is that the problem is somehow related to the update from the thread (which emits a signal that is caught and in turn just calls the UpdateDisplay function). The reason I think so is that if I comment out the signals and just create a new button to call the UpdateDisplay with some bogus information, everything is fine.
A qApp->processEvents() before the offending line has no effect.
I am stuck here. Any ideas are welcome. For instance, is there any test I can do to verify that calling the clear() method is ok?
I finally tracked this problem down to a nasty memory leak in my code. I "repaired" the code but I am still a little bit puzzled by why the problem was happening.
Basically, I was creating a large vector<double> somewhere and passing its address to a function that called for a vector<double> * variable. The problem was that the original vector ceased to be before the function finished working with. Classic dumb mistake. Probably the QPlainTextEdit document was allocating space in the area where the vector<double> used to be: erratic behavior expected. But I would not expect a crash.
The vector was "read-only". The function using it, only read the values and made calculations stored somewhere else. Let's now assume that the plain text creates something in the memory previously addressed by the vector<double>. In this case, when I QPlainTextEdit::clear() the plain text document, the values previously pointed by the vector change and I would expect the calculations to be non sense. I would also accept a crash when the function access the now deceased pointer to vector<double>. But I would not expect the program to crash when I clear the text, which after all is a valid pointer.
Anyway, if anybody has a though, I'd be curious to know why the crash happens. But otherwise, the problem is gone once the leak was repaired. And of course, knowing the reason is absolutely no excuse to not repair the leak.

How to issue signal each time a row is edited in QListWidget?

class genericTaskList : public QListWidget
{
Q_OBJECT
public:
QListWidgetItem *defaultText;
genericTaskList (QWidget *parentWidget)
{
setParent (parentWidget);
setFixedSize (445, 445);
defaultText = new QListWidgetItem ("Double click here to compose the task");
defaultText->setFlags (defaultText->flags () | Qt :: ItemIsEditable);
insertItem (0, defaultText);
QObject :: connect (this, SIGNAL (currentRowChanged (int)), this, SLOT (addDefaultText (int)));
}
public slots:
void addDefaultText (int rr)
{
std::cout << "\ndsklfjsdklfhsdklhfkjsdf\n";
insertItem (++rr, defaultText);
}
};
This code is supposed to issue a signal each time the row gets edited.
After I call "insertItem" in the constructor, the signal is issued.
But, that's it. It never gets issued after that - no matter how many times I edit the row.
What am I missing?
At first it seems like QListWidget::itemChanged is the way to go, but soon you run into a problem: the signal is sent for everything - inserts, removes, changing colors, checking boxes, etc! So then you end up trying to put in flags and filter everywhere by intercepting various signals to find out if editing was the actual event. It gets very messy.
There is also QAbstractItemModel::dataChanged , which would seem like a good solution. It even has a parameter "const QVector& lstRoles" so you could scan for Qt::EditRole and see if it was really edited. Alas, there's a catch - it gets called for everything just like QListWidget::itemChanged and unfortunately, for QListWidget anyway, the roles parameter is always empty when it's called (I tried it). So much for that idea...
Fortunately, there's still hope... This solution does the trick! :
http://falsinsoft.blogspot.com/2013/11/qlistwidget-and-item-edit-event.html
He uses QAbstractItemDelegate::closeEditor, but I prefer using QAbstractItemDelegate::commitData.
So make a connect like so...
connect(ui.pLstItems->itemDelegate(), &QAbstractItemDelegate::commitData, this, &MyWidget::OnLstItemsCommitData);
Then implement the slot like this...
void MyWidget::OnLstItemsCommitData(QWidget* pLineEdit)
{
QString strNewText = reinterpret_cast<QLineEdit*>(pLineEdit)->text();
int nRow = ui.pLstItems->currentRow();
// do whatever you need here....
}
Now you have a slot that gets called only when the list item's text has been edited!
currentRowChanged indicates the row selection has changed, not the content of the row. Perhaps you want to use currentTextChanged or itemChanged instead.
The reuse of the word current and changed in the QT docs is quite confusing.
Warning: A QListWidgetItem can only be added to a QListWidget once. Adding the same QListWidgetItem multiple times to a QListWidget will result in undefined behavior.
So even if it will emit the signal I think you should better to add newly created Item.
And when do you want the new row to be inserted ? -
as soon as item is double clicked or finishing edit - they differ.