[Python-modules-team] Bug#599612: python-qt4: removeItemWidget() wrongly removes QTreeWidgetItem itself
Leonardo Vainsencher
elweins at gmail.com
Sat Oct 9 15:01:40 UTC 2010
Package: python-qt4
Version: 4.7.3-1+b1
Severity: normal
In a Python program I use setItemWidget() to add widgets to columns
of QTreeWidgetItems (eg QPushButton, QComboBox, etc).
When a widget is no longer needed it is removed using removeItemWidget(),
however this action causes the removal of the QTreeWidgetItem itself
instead of just removing the item widget attached by setItemWidget().
Problem goes away if extra references to QTreeWidgetItems are kept
somewhere outside the QTreeWidget instance.
This problem does not occur in a C++ implementation.
Files attached can help demonstrate the issue:
bug.py:
Python script demonstrating the bug; if run without arguments
bug shows up (disappearing QTreeWidgetItems); if run with a single
argument 'workaround' the script artificially keeps extra references
causing QTreeWidgetItems to stay in their places; program uses a
timer to add and remove item widgets after short delays;
ctl-Q quits the program.
bug.ui:
GUI file from designer-qt4 for both python version and C++ version.
bug.cpp bug.h:
C++ "translation" of bug.py; shows setItemWidget/removeItemWidget
working as expected.
bug.mk
Simple Makefile to compile everything.
*** bug.py
#! /usr/bin/python
from PyQt4 import QtGui as Qg
from PyQt4 import QtCore as Qc
from PyQt4 import Qt
from ui_bug import Ui_MainWindow
import sys
class MainWindow(Qg.QMainWindow, Ui_MainWindow):
def __init__(self, workaround=True):
Qg.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.connect(self.actionExit, Qc.SIGNAL('triggered()'), self.__exit)
self.__timer = Qc.QTimer(self)
self.connect(self.__timer, Qc.SIGNAL('timeout()'), self.__sequence)
self.__state = 0
self.__timer.setSingleShot(True)
self.__timer.start(2000)
if workaround:
print 'WARNING: using removeItemWidget() bug workaround'
tw = self.treeWidget
nitems = tw.topLevelItemCount()
self.__items = [tw.topLevelItem(k) for k in range(nitems)]
else: self.__items=[]
def __sequence(self):
treew = self.treeWidget
nitems = treew.topLevelItemCount()
if nitems < 1:
print 'ERROR: no items left'; return
col = 1
if self.__state==0:
print 'adding %d item widgets to column %d' % (nitems,col)
for k in range(nitems):
item = treew.topLevelItem(k)
pbut = Qg.QPushButton(item.text(col),self)
treew.setItemWidget(item, col, pbut)
item.setText(col, '')
self.__state+=1
self.__timer.start(2000)
elif self.__state==1:
print 'removing %d item widgets from column %d' % (nitems,col)
for k in range(nitems):
item = treew.topLevelItem(k)
pbut = treew.itemWidget(item, col)
item.setText(col, pbut.text())
treew.removeItemWidget(item, col)
self.__state+=1
self.__timer.start(2000)
def __exit(self):
Qg.QApplication.closeAllWindows()
if __name__ == '__main__':
app = Qg.QApplication([])
gui = MainWindow('workaround' in sys.argv[1:])
gui.show()
sys.exit(app.exec_())
*** bug.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeWidget" name="treeWidget">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<column>
<property name="text">
<string>1</string>
</property>
</column>
<column>
<property name="text">
<string>2</string>
</property>
</column>
<column>
<property name="text">
<string>3</string>
</property>
</column>
<item>
<property name="text">
<string>a</string>
</property>
<property name="text">
<string>b</string>
</property>
<property name="text">
<string>c</string>
</property>
</item>
<item>
<property name="text">
<string>x</string>
</property>
<property name="text">
<string>y</string>
</property>
<property name="text">
<string>z</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>26</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionExit"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
*** bug.cpp
#include "bug.h"
#include "ui_bug.h"
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QPushButton>
#include <iostream>
#include <boost/format.hpp>
using namespace std;
using boost::format;
MainWindow::MainWindow(void)
{
_state = 0;
_timer = new QTimer(this);
_priv = new Ui_MainWindow;
_priv->setupUi(this);
connect(_priv->actionExit, SIGNAL(triggered()), SLOT(_exit()));
connect(_timer, SIGNAL(timeout()), SLOT(_sequence()));
_timer->setSingleShot(true);
_timer->start(2000);
}
void MainWindow::_exit(void)
{
QApplication::closeAllWindows();
}
void MainWindow::_sequence(void)
{
QTreeWidget* treew= _priv->treeWidget;
const int nitems= treew->topLevelItemCount();
if (nitems < 1) {
cout << "ERROR: no items left" << endl;
return;
}
const int col=1;
if (_state==0) {
cout << format("adding %d item widgets to column %d\n") % nitems % col;
for (int k=0; k < nitems; k++) {
QTreeWidgetItem* item= treew->topLevelItem(k);
QPushButton* pbut= new QPushButton(item->text(col), this);
treew->setItemWidget(item, col, pbut);
item->setText(col, "");
}
_state+=1;
_timer->start(2000);
} else if (_state==1) {
cout << format("removing %d item widgets from column %d\n") % nitems % col;
for (int k=0; k < nitems; k++) {
QTreeWidgetItem* item= treew->topLevelItem(k);
QPushButton* itemw=
dynamic_cast<QPushButton*>(treew->itemWidget(item, col));
item->setText(col, itemw->text());
treew->removeItemWidget(item, col);
delete itemw;
}
_state+=1;
_timer->start(2000);
}
}
int main(int ac, char** av)
{
QApplication app(ac,av);
MainWindow gui;
gui.show();
return app.exec();
}
*** bug.h
#ifndef BUG_H
#define BUG_H
#include <QtGui/QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(void);
private slots:
void _exit(void);
void _sequence(void);
private:
class Ui_MainWindow* _priv;
class QTimer* _timer;
int _state;
};
#endif
*** bug.mk
uiparts = bug.ui
uihdrs = bug.h
sources = bug.cpp
target = bug.exe
pyuis = $(uiparts:%.ui=ui_%.py)
ccuis = $(uiparts:%.ui=ui_%.h)
mocs = $(uihdrs:%.h=moc_%.cpp)
qtinc = /usr/include/qt4
qtlib = -L/usr/lib/qt4/lib
INCL = -I$(qtinc)/QtCore -I$(qtinc)/QtGui -I$(qtinc)
LIBS = $(qtlib) -lQtGui -lQtCore
.IGNORE: all
all: $(pyuis) $(target)
$(target): $(mocs) $(sources) $(uihdrs) $(ccuis)
g++ -g -o $@ $(INCL) $(mocs) $(sources) $(LIBS)
ui_%.py: %.ui
pyuic4 -x -o $@ $<
ui_%.h: %.ui
uic-qt4 -o $@ $<
moc_%.cpp: %.h
moc-qt4 -o $@ $(INCL) $<
-- System Information:
Debian Release: squeeze/sid
APT prefers testing
APT policy: (500, 'testing')
Architecture: i386 (i686)
Kernel: Linux 2.6.32-5-686 (SMP w/4 CPU cores)
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
Shell: /bin/sh linked to /bin/bash
Versions of packages python-qt4 depends on:
ii libc6 2.11.2-6 Embedded GNU C Library: Shared lib
ii libgcc1 1:4.4.4-8 GCC support library
ii libpython2.6 2.6.6-3 Shared Python runtime library (ver
ii libqt4-assistant 4:4.6.3-1+b1 Qt 4 assistant module
ii libqt4-designer 4:4.6.3-1+b1 Qt 4 designer module
ii libqt4-help 4:4.6.3-1+b1 Qt 4 help module
ii libqt4-network 4:4.6.3-1+b1 Qt 4 network module
ii libqt4-script 4:4.6.3-1+b1 Qt 4 script module
ii libqt4-scripttools 4:4.6.3-1+b1 Qt 4 script tools module
ii libqt4-svg 4:4.6.3-1+b1 Qt 4 SVG module
ii libqt4-test 4:4.6.3-1+b1 Qt 4 test module
ii libqt4-webkit 4:4.6.3-1+b1 Qt 4 WebKit module
ii libqt4-xml 4:4.6.3-1+b1 Qt 4 XML module
ii libqt4-xmlpatterns 4:4.6.3-1+b1 Qt 4 XML patterns module
ii libqtcore4 4:4.6.3-1+b1 Qt 4 core module
ii libqtgui4 4:4.6.3-1+b1 Qt 4 GUI module
ii libstdc++6 4.4.4-8 The GNU Standard C++ Library v3
ii python 2.6.5-13 interactive high-level object-orie
ii python-sip [sip-api-7.1] 4.10.2-1 Python/C++ bindings generator runt
ii python-support 1.0.10 automated rebuilding support for P
python-qt4 recommends no packages.
Versions of packages python-qt4 suggests:
pn python-qt4-dbg <none> (no description available)
-- no debconf information
More information about the Python-modules-team
mailing list