How to properlly use setUpdatesEnabled to help GUI performance?
Here is my code:
void uavTabGroup::updateMgr()
{
setUpdatesEnabled(false);
for (updateCtr = 0; updateCtr < max_num; updateCtr++)
{
if (infoView[updateCtr] != NULL)// its a child widget to the current widget
{
infoView[updateCtr]->updateDisplay();
}
}
setUpdatesEnabled(true);
}
However, there is no improvement compared to don't use setUpdatesEnalbed() function, am I doing this wrong. BTW, all the infoView[i] are in a girdlayout of the current widget.
Now I am doing the updating in this way:
void uavTabGroup::updateMgr()
{
if (updateCtr >= max_num)
updateCtr = 0;
if (infoView[updateCtr] != NULL)
{
infoView[updateCtr]->updateDisplay();
}
updateCtr++;
}
And trigger the updateMgr at a higher frequency, and the child widgets are getting updated one by one sequentially.
But someone told me this is wrong... So which is the correct solution?
Related
I have a fixed-length List that is used in the "build" function. I want to replace one element in that List with another. Both elements in the List are Containers. I replace the element in the List and do a setState(). The build function uses the List in the body of the Scaffold. I get no error, however when the rebuild is done, nothing has changed.
To my knowledge this is not breaking any rules and as far as I know should cause no problems.
While I could code around the issue, I think that with something as fundamental as this, I need to find the reason for it.
Any ideas as to why this is happening?
Code added below:
Below is the code that DOES NOT work
if (_lwDisplay[iNdxDisplay] == null) /*INITIAL DISPLAY */ {
_lwDisplay[iNdxDisplay] = wContainer;
} else {
setState(() {
_tfDataHasChanged = true;
_lwDisplay[iNdxDisplay] = wContainer;
});
}
Below is the code that DOES work
if (_lwDisplay[iNdxDisplay] == null) /*INITIAL DISPLAY */ {
_lwDisplay[iNdxDisplay] = wContainer;
} else {
_tfDataHasChanged = _fnHasDataChanged() /* FOR FAB */;
List<Widget> lwDisplay2 = List(_lwDisplay.length);
for (int iNdx = 0; iNdx < lwDisplay2.length; iNdx++) {
if (iNdx != iNdxDisplay) {
lwDisplay2[iNdx] = _lwDisplay[iNdx];
}
}
lwDisplay2[iNdxDisplay] = wContainer;
_lwDisplay = lwDisplay2;
setState(() {});
}
Without seeing the entirety of code, and according to this SO question,
Move the instantiation of the list of widgets to the build method of your main widget.
I.E.
class MainWidgetState extends State<MainWidget> {
List<YOUR_WIDGET> _lwDisplay = new List();
Widget build(BuildContext context) {
//Create your list
}
}
Also, add a key to each item in your widget (if you haven't done so already).
I'm developing an program that allows you to communicate with an Engine control unit of a small turbine. The ECU is configured using 255 8-bit numbers stored in an EEPROM (ECU communicates over RS232). each number represents one of the engine's settings.
So to make sense of this we have a file that describes the meaning of all these settings and this is loaded into my program, which generates a row of 15 standard QWidgets per setting.
I also implemented a way to categorize these settings, for example, all fuel consumption related settings belong to one category. there's a Qcombobox in which you can select which category you want to filter. clicking it calls the following function:
void MainWindow::on_listCategories_currentTextChanged(const QString ¤tcategory) { //filter categories
//ui->checkBoxShowDifferences->setCheckState(Qt::Unchecked); //ugly hack!!
setUpdatesEnabled(false);
if(currentcategory == "ALL") {
for(int i=0; i<RegistrySettings.size(); i++) {
if(RegistrySettings[i].Policy < static_cast<int>(TMC_Program.CurrentActiveAccessPolicy)) {
hideOptionWidgets(RegistrySettings[i].address);
continue;
}
if(ui->checkBoxShowDifferences->isChecked()) {
if(RegistrySettings[i].value == RegistrySettings[i].compareValue) {
hideOptionWidgets(RegistrySettings[i].address);
continue;
}
}
showOptionWidgets(RegistrySettings[i].address);
}
} else {
for(int i=0; i<RegistrySettings.size(); i++) {
if(RegistrySettings[i].Policy < static_cast<int>(TMC_Program.CurrentActiveAccessPolicy)) {
hideOptionWidgets(RegistrySettings[i].address);
continue;
}
if(RegistrySettings[i].category != currentcategory) {
hideOptionWidgets(RegistrySettings[i].address);
continue;
}
if(ui->checkBoxShowDifferences->isChecked()) {
if(RegistrySettings[i].value == RegistrySettings[i].compareValue) {
hideOptionWidgets(RegistrySettings[i].address);
continue;
}
showOptionWidgets(RegistrySettings[i].address);
} else {
hideOptionWidgets(RegistrySettings[i].address);
}
}
}
setUpdatesEnabled(true);
while hiding works perfectly fine, when selecting "ALL" it needs to show all the hidden widgets, this is incredibly slow! it takes around 5 seconds to display all the widgets!
The code responsible for showing all the widgets is this:
void MainWindow::showOptionWidgets(int addr) {
if(addr < 0 || addr > 255) {return;}
QStringList WidgetNames = generateOptionRowWidgetNames(addr);
for(int i=1; i<WidgetNames.size(); i++) { //number 0 is a qhboxlayout and not a qwidget so it won't find it
QWidget* widgetToShow = ui->scrollAreaOptions->findChild<QWidget*>(WidgetNames[i]);
if(widgetToShow && widgetToShow->isHidden()) {
widgetToShow->show(); //extremely slow!
}
}
}
is there a way to optimize this?
note: all widgets are standard ones! just labels, checkboxes and buttons, generate optionRowWidgetNames only generates a simple QStringlist with fixed strings that only have the corrosponding settings number attached to them.
I used a QTimer to control when should I update my widgets.
Many people suggested to do:
void uavTabGroup::updateMgr()
{
setUpdatesEnabled(false);
for (updateCtr = 0; updateCtr < max_num; updateCtr++)
{
if (infoView[updateCtr] != NULL)// its a child widget to the current widget
{
infoView[updateCtr]->updateDisplay();
}
}
setUpdatesEnabled(true);
}
But I found that to update the widgets sequentially give me better results:
void uavTabGroup::updateMgr()
{
if (updateCtr >= max_num)
updateCtr = 0;
if (infoView[updateCtr] != NULL)
{
infoView[updateCtr]->updateDisplay();
}
updateCtr++;
}
In this case the updateMgr() is called at higher frequency, but for each time only one of its child widget is updated.
What is the best way?
I'm writing an application that has a QTreeWidget that is populated by parsing an XML file containing the tree levels. If I select a top level checkbox, I need all of the sub-level checkboxes to be checked also.
I already have the XML parser working and populating the QTreeWidget with QTreeWidgetItems that have checkboxes but they can only be individually checked.
To do this, keep the code you have to generate the tree with your XML. Then connect to the itemChanged() signal and update the check states in a slot. It should look something like:
connect(treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
this, SLOT(updateChecks(QTreeWidgetItem*, int)));
void ClassName::updateChecks(QTreewidgetItem* item, int column)
{
// Checkstate is stored on column 0
if(column != 0)
return;
recursiveChecks(item);
}
void ClassName::recursiveChecks(QTreeWidgetItem* parent)
{
Qt::CheckState checkState = parent->checkState(0);
for(int i = 0; i < parent->childCount(); ++i)
{
parent->child(i)->setCheckState(0, checkState);
recursiveChecks(parent->child(i));
}
}
A few notes to consider:
You may be tempted to use the itemClicked signal instead of the itemChanged signal. This usually works, but will not work when the user uses the arrow keys and the space bar to change checkstates.
You will need to think about what will happen when you uncheck one of the sub-items that have been checked by clicking on its parent. Usually this means you need to make all ancestors either uncheck or partially-checked. This may not be true for your case.
itemUpdated will also get fired for other changes to the item (like the text changing), so be aware that this is not a super efficient way of doing this.
I just worked on this a little and got nice results based on Rick's answer. Maybe it can help other out there.
It updates the state of parents and children with a tristate status for parents only (checked, unchecked, partially-checked).
void ClassName::updateChecks(QTreeWidgetItem *item, int column)
{
bool diff = false;
if(column != 0 && column!=-1)
return;
if(item->childCount()!=0 && item->checkState(0)!=Qt::PartiallyChecked && column!=-1){
Qt::CheckState checkState = item->checkState(0);
for (int i = 0; i < item->childCount(); ++i) {
item->child(i)->setCheckState(0, checkState);
}
} else if (item->childCount()==0 || column==-1) {
if(item->parent()==0)
return;
for (int j = 0; j < item->parent()->childCount(); ++j) {
if(j != item->parent()->indexOfChild(item) && item->checkState(0)!=item->parent()->child(j)->checkState(0)){
diff = true;
}
}
if(diff)
item->parent()->setCheckState(0,Qt::PartiallyChecked);
else
item->parent()->setCheckState(0,item->checkState(0));
if(item->parent()!=0)
updateChecks(item->parent(),-1);
}
}
Doesn't need recursiveChecks() anymore. Connect between the treeWidget and updateChecks still active.
This appears still quite high in search engines, and is outdated.
Just set the flag Qt::ItemIsAutoTristate on your top-level item.
I have a set of codes in my function with a lot of if-else loops but each doing a diffrent one
like
if(ddlname.SelectedIndex = 0)
{
//do this
}
else
{
//do this
}
if (txtprice.Text ="")
{
//do tis
}
else
{
//do this
}
my whole program looks clumsy and unnecessarily long because of this one. I have some 20 dropdownlists and ten textboxes. Is there way to make this as simple as 1 or 2 for loops ?
I am currently reading Clean Code by Robert C. Martin. According to his book, you should refactor your method into several smaller methods, doing exactly one thing. You should for example extract every do this into its own method.
As to your question, I don't think there is any way of achieving the same logic using for loops, unless you do the same for every call.
foreach (ctl in page.ctls)
{
TextBox tempTextBox = ctl as TextBox;
if (tempTextBox != null)
{
doTheSameForEveryTextBox(tempTextBox)
}
DropDownList tempDropDownList as DropDownList; // not sure if this is the right Type...
if (tempDropDownList != null)
{
doTheSameForEveryTextBox(tempDropDownList)
}
}
void doTheSameForEveryTextBox(TextBox tempTextBox)
{
if (tempTextBox.Text == "")
{
//TODO: implement your code here
}
}
void doTheSameForEveryDropDownList(DropDownList tempDropDownList)
{
if (tempDropDownList.SelectedIndex == 0)
{
//TODO: implement your code here
}
}