QDoubleSpinBox thousand separator while user is typing - qt

I want to make a QDoubleSpinBox that would format the value into currency so it would be readable by users.
Example.
So far I've accomplished these things:
set showGroupSeparator to true - but it will only work when focus is released.
used the valueChanged signal to update the group separators directly by calling ui->doubleSpinBox->setValue(amount);
void DialogCashPayment::on_sbAmount_valueChanged(double arg1)
{
ui->sbAmount->setValue(arg1);
}
The Problem is
The cursor position will not be in the correct position when the
amount is > than 10k, sometimes the amount will completely disappear.
in short its really buggy.
Is there any approach on this? Maybe I've overlooked something simple. Please raise a comment if something is not clear. Thanks!

Related

QTextEdit or QTextBrowser performance issue

I have a heavy QString.
I need to display it as an output.
I tried both QTextEdit or QTextBrowser. And all methods of setting text like setText, append, setPlainText.....The performance is really poor. The most annoying things is that setting thing on user interface meaning blocking the main thread. So the program will become unresponsive during the process.
Is there any better way to display visual text result?
At least if the document is rich text, every time you append to the document, it is apparently reparsed.
This is A LOT more performant: If you want each append to actually show quickly & separately (instead of waiting until they've all been appended before they are shown), you need to access the internal QTextDocument:
void fastAppend(QString message,QTextEdit *editWidget)
{
const bool atBottom = editWidget->verticalScrollBar()->value() == editWidget->verticalScrollBar()->maximum();
QTextDocument* doc = editWidget->document();
QTextCursor cursor(doc);
cursor.movePosition(QTextCursor::End);
cursor.beginEditBlock();
cursor.insertBlock();
cursor.insertHtml(message);
cursor.endEditBlock();
//scroll scrollarea to bottom if it was at bottom when we started
//(we don't want to force scrolling to bottom if user is looking at a
//higher position)
if (atBottom) {
scrollLogToBottom(editWidget);
}
}
void scrollLogToBottom(QTextEdit *editWidget)
{
QScrollBar* bar = editWidget->verticalScrollBar();
bar->setValue(bar->maximum());
}
The scrolling to bottom is optional, but in logging use it's a reasonable default for UI behaviour.
This actually seems a kind of trap in Qt. I would know why there isn't a fastAppend method directly in QTextEdit? Or are there caveats to this solution?
(My company actually paid KDAB for this advice, but this seems so silly that I thought this should be more common knowledge.)
Original answer here.
Just got the same problem, and the resolution is very simple! Instead of creating a document + adding it immediately to the QTextBrowser/QTextEdit and then use cursor/set text to modify it, just postpone setting the document to the widget till AFTER you set the text / formatting... a complete life changer :)
The best way would be to load text partially as background operation with thread that periodically emit signal to redraw GUI, or better: just use QTimer.
Load first N lines, and then start QTimer that'll read more lines and append text inside widget. After reaching eof just kill that timer.
I believe that example can be helpful.

Programming: Detect the direction and stop of change of a number

Any language, just pseudocode.
I'm searching around for an algorithm that detects direction and the stop of changes to a number. E.g.:
function detectChange(int number) {
if number is rising return "rising"
if number is dropping return "dropping"
if number is unchanged return "unchanged"
}
main() {
int number
while(true) {
//The read doesn't always happen
if readObscure.readoccured() {
//read the number from an obscure source
number = readObscure()
print(detectChange(number))
}
}
}
I've been working on an approach with a time delta but with little success. One problem is e.g. that with the timing approach I always miss the last change. Maybe I could solve that too but it's already pretty hacky.
So I'd be glad about a clean "textbook" solution, preferably without using time but just logic. If there's none without time, but still a clean solution, I'd appreciate that too.
Solution can be written in any "human readable" language (no haskell please) or pseudocode, I don't care.
I should have mentioned that the readObscure() function may also return the same number over and over again, or won't return a number at all, in which case I want to assume that the number is "unchanged".
Let's also update this with some examples:
readObscure() returns the numbers 1,2,14,15,8,17,20
This should be "rising"
readObscure() returns the numbers 1,2,14,15,17,20,20,20
This should be "rising" and then "unchanged"
So the question also is, how to define rising, unchanged, dropping. I'd like someone who maybe worked on those problems before to define it. The result should equal a "human sorting", so I look at the numbers and can immediatly tell, they are not rising, or they are rising.
I've been made aware of Rx (Reactive Extensions)
But for my personal case this is using a sledge-hammer to crack a nut.
Just make it so that whenever you add a value:
Take the value of the current and the last value, compute its delta.
Then, add it to wherever you're holding the deltas.
If you want something to "fire" everytime you "add a value," it's probably best to bind it to the container or some sort of callback/event-based mechanism/structure to ensure this. Boost.Signals2 (C++) is supposed to be a good way to handle this, but something as simple as creating an asynchronous thread of execution to compute and then push your value to the back of the storage vector would be good enough.

Qt - signal for when QListWidget row is edited?

I am working in Qt4.7, and I have a QListWidget in my dialog. I have a QString that needs to match the current text in the row of this widget (the individual rows are editable). Looking at the signals associated with QListWidget, there seem to be signals for when a different index is selected but none for when the text of a the currently selected row changes. I thought currentTextChanged(QString) would do it, but it didn't. I also thought to try to connect each individual row to something, but QListWidgetItem doesn't have any built-in signals. Does anyone know of a way to do this? Thanks!
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, changing colors, checking boxes, and anything else that "changes" the item! Predelnik pointed that out in his answer. Some people have tried 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!
I guess you need to look into the following signal:
void QListWidget::itemChanged(QListWidgetItem * item)
But be careful because it's being sent every time some property of item changed, not only text. I remember when we ran into the problem once when we changed item colors and got tons of false positive slots called because of that. If you need more fine tuning I guess it's better to write model/view classes yourself and not rely on QListWidget.

Flash/Flex: "Warning: filter will not render" problem

In my flex application, I have a custom TitleWindow that pops up in modal fashion. When I resize the browser window, I get this warning:
Warning: Filter will not render. The DisplayObject’s filtered dimensions (1286, 107374879) are too large to be drawn.
Clearly, I have nothing set with a height of 107374879.
After that, any time I mouse over anything in the Flash Player (v. 10), the CPU churns at 100%. When I close the TitleWindow, the problem subsides. Sadly, the warning doesn't seem to indicate which DisplayObject object is too large to draw. I've tried attaching explicit height/widths to the TitleWindow and the components within, but still no luck.
[Edit]
The plot thickens:
I found that the problem only occures when I set the PopUpManager's createPopUp modal parameter to "true." I don't see the behavior when modal is set to "false." It's failing while applying the graying filter to other components that comes from being modal. Any ideas how I can track down the one object that has not been initialized but is being filter during the modal phase?
Thanks for reading.
This might not be the case in your application, but I have come across similar cases where a height or width of an object has been set to some unreasonable big number as the result of misuse of an unsigned integer in calculations for positioning, height or width.
Schematic code for such a scenario could be like this:
var offset:uint = 30;
var position:uint = txt.textHeight - offset;
divider.y = position;
The code wrongfully assumes that txt.textHeight will always be bigger than 30. If it is not, txt.textHeight - offset will be a negative number, that when stored in an uint will instead become a very large number.
Let's say for example that the text in txt, presumed to be a long multiline text, instead is a single line that is 20 pixels heigh. The result will then be -10, and when stored in the uint var position, the value of position will be 4294967286.
The above is crappy code, an example, but in a real world situation the uint problem can occur in some more complex way, that might be harder to spot right away. I guess it is seldom a good idea to use an unsigned integer for stuff like x and y positions, that can have negative values.
You could write some code to recursively step down the hierarchy of DisplayObjectContainer and DisplayObject objects and check for the large height.
Should be pretty simple to write. A function something like this should do the trick:
function RecurseDisplayObjects(DisplayObject obj):void
{
//check for height and do a trace() or whatever here
if(obj is DisplayObjectContainer)
{
var container:DisplayObjectContainer = obj as DisplayObjectContainer;
for(var i:int=0; i<container.numChildren; i++)
{
RecurseDisplayObjects(container.getChildAt(i);
}
}
}
You would need to start this off by passing it the top level DisplayObject in your application. (possibly obtained with DisplayObject.root)
The other option you have is to get the Flex framework source and modify it to give you a more meaningful error.
The problem is probably not in your TitleWindow, but in objects below it. The filter failing to render is probably the blur filter flash applies over everything below the modal dialog. If one of the objects on the stage is too big to apply blur on it in real time, you get the error you mentioned.
I solved that problem by applying a mask to the object below the titlewindow, set to the size of the stage. That will probably solve your problem but you should definitely look into why something gets to that size, doesn't sound healthy. :-)
Sadly I have no idea, but we're trying to track down a similar issue in ours. Maybe this will help?
http://www.mail-archive.com/flashcoders#chattyfig.figleaf.com/msg48091.html
I had a similar issue, tracked it down to an alpha filter applied to an object scaled to -0.23453422334. Once I rounded the scale to 2 significant digits everything worked fine. A difficult error to track down however.

Flex - Is there a way to specify what direction a ComboBox will open?

Maybe I should further qualify this - Is there a way to specify which direction a ComboBox will open without copying and pasting the entire ComboBox class and ripping out the code where it determines which direction it will open in...
I'm my specific case - I need it to open upwards - always.
UPDATE: You can't fix this by subclassing it because the function that handles the direction of the opening is:
private function displayDropdown(show:Boolean, trigger:Event = null):void
And that bad boy uses a fair amount of private variables which my subclass wouldn't have access to...
If you build up the Menu object yourself, you can place the menu anywhere you want by simply setting the x,y coordinates of the menu object. You'll need to calculate those coordinates, but you might be able to do this easily without subclassing ComboBox.
I am doing something similar with PopUpButton; you might find it easier to work with PopUpButton. This is based on real code from my current project:
private function initMenu(): void {
var m:Menu = new Menu();
m.dataProvider = theMenuData;
m.addEventListener(MenuEvent.ITEM_CLICK, menuClick);
m.showRoot = false;
// m.x = ... <-- probably don't need to tweak this.
// m.y = ... <-- this is really the interesting one :-)
theMenu.popUp = m;
}
<mx:PopUpButton id="theMenu" creationComplete="initMenu()" ... />
BTW, to get the PopUpButton to act more like I wanted it (always popup, no matter where the click), setting openAlways=true in the MXML works like a charm.
I doubt it - you'd need to subclass the control (which isn't that big a deal.)
Maybe you could mess with the real estate so it's placed in such a fashion (e.g. crowded into the lower right corner) that up is naturally coerced?
I would recommend checking out this post. Yes, you do have to grab the ComboBox code and modify it, but at least now you have an idea where the modifications need to go.
You could set the MaxDropDownHeight, if you set it big enough Windows will automatically set the direction upwards.
This irritated me no end. I have uploaded a solution, its a simple Class that extends the PopUpButton and removes the logic of stage bounds detection as it failed 50% of the time anyway. My code just allows you to simply specify whether you want to open the menu up or down:
http://gist.github.com/505255

Resources