PyQt4: Items disappear when using Drag and Drop with QComboBox - drag-and-drop

I would like to use drag-and-drop to rearrange the items in a QComboBox. I tried this:
from PyQt4.QtGui import QApplication, QComboBox, QAbstractItemView
a = QApplication([''])
c = QComboBox()
c.addItem('a')
c.addItem('b')
c.addItem('c')
c.addItem('d')
view = c.view()
view.setDragDropMode(QAbstractItemView.InternalMove)
c.show()
c.raise_()
a.exec_()
However, dragging an item on top of another item deletes the dragged item -- I want that item to be moved above/below the drop location. Am I doing this incorrectly?

Each combo item needs to be disabled as a drop target by setting the appropriate item flags.
Here's one way to achieve that:
import sys
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication(sys.argv)
combo = QtGui.QComboBox()
model = QtGui.QStandardItemModel()
for text in 'One Two Three Four'.split():
item = QtGui.QStandardItem(text)
item.setFlags(item.flags() & ~QtCore.Qt.ItemIsDropEnabled)
model.appendRow(item)
combo.setModel(model)
combo.view().setDragDropMode(QtGui.QAbstractItemView.InternalMove)
combo.show()
app.exec_()

Related

Perl Gtk3::ScrolledWindow that contains more than one Gtk3::TreeView child. How do you disable child from scrolling to the top when selecting a row?

I am writing a program in Perl using Gtk3. I have a left sidebar (not using any sidebar widgets) that contains multiple tree views.
I it setup like this:
my $sidebarscrollarea = Gtk3::ScrolledWindow->new( undef, undef );
my $sidebarlabelaccounts = Gtk3::Label->new("Accounts");
$sidebarlabelaccounts->set_halign('GTK_ALIGN_START');
my $sidebarlabelincome = Gtk3::Label->new("Income Envelopes");
$sidebarlabelincome->set_halign('GTK_ALIGN_START');
my $sidebarlabelexpense = Gtk3::Label->new("Expense Envelopes");
$sidebarlabelexpense->set_halign('GTK_ALIGN_START');
# *_create_model() builds the models
my $account_tstore = account_create_model();
my $income_tstore = envelope_create_model();
my $expense_tstore = envelope_create_model();
# populate the models with another subroutine
populate_models();
my $accountslist = Gtk3::TreeView->new();
$accountslist->set_model($account_tstore);
my $incomelist = Gtk3::TreeView->new();
$incomelist->set_model($income_tstore);
my $expenselist = Gtk3::TreeView->new();
$expenselist->set_model($expense_lstore);
# Add columns to model and view via view ( Gtk3::TreeView )
account_add_columns($accountslist);
envelope_add_columns($incomelist);
envelope_add_columns($expenselist);
my $sidebarbox = Gtk3::Box->new('vertical',1);
$sidebarbox->set_border_width(5);
$sidebarbox->pack_start($sidebarlabelaccounts,0,0,5);
$sidebarbox->pack_start($accountslist,0,6,5);
$sidebarbox->pack_start($sidebarlabelincome,0,0,5);
$sidebarbox->pack_start($incomelist,0,6,0);
$sidebarbox->pack_start($sidebarlabelexpense,0,0,5);
$sidebarbox->pack_start($expenselist,0,6,0);
$sidebarscrollarea->add($sidebarbox);
The envelopeslist is very long. When I click a row from that list that is toward the bottom of the window, it scrolls so that the envelopes list at the top of the window. I do not want it to move anywhere regardless of where I click a row. Thanks for your help. I am new to all of this.
Simply adding:
$expenselist->set_can_focus(FALSE);
solves my problem.

adding/changing 'text' to an item in a group

I'm designing a UI with Enthought's TraitsUI, and I can't figure out how to get done what I want...
Here's what I want:
I have Items() in the view that I want to display as either English or SI units. I can change the value in the 'edit' box based on a SI/English button, but I can't figure out how to change the text of the label. For example, if I have an item 'Length, ft [ 3.28]' and convert it to SI, I'd like it to show 'Length, m [ 1.00]'. I can handle the 3.28->1.00 conversion, but can't figure out how to change the 'ft' to 'm'.
Any suggestions?
One thing I've tried is to define a string which holds the units name (like 'm' or 'ft')...then, in the item, I set the label like this:
label = 'Top, '+lengthUnits
This works fine when the view is first built, but it doesn't update the label when I change the units control. Is there some way to force the view to update with all the new values?
Here's a small py program that shows what I'm trying to do (feel free to critique my style :)). I'll also try and add in a couple of images that shows what happens:
# NOTE: This version of the code has been modified so that it works as I want it to :)
# Example trying to change text on a View...
from traits.api \
import HasTraits, Enum, CFloat, String
from traitsui.api \
import View, Group, HGroup, Item, spring
class TestDialog ( HasTraits ):
length = CFloat(1.0)
choose_units = Enum('English', 'SI')
current_units = 'English'
unit_name = String('ft')
ft_to_m = CFloat(3.28)
view = View(
Group(
HGroup(
spring,
Item(name = "length", label = 'Test length'),
Item(name = 'unit_name', style = 'readonly', show_label = False),
spring
),
HGroup(
spring,
Item(name = "choose_units"),
spring
)
),
title = 'Test Changing View Test'
)
def _choose_units_changed(self):
if self.current_units != self.choose_units:
if self.choose_units == 'SI':
self.length /= self.ft_to_m
self.unit_name = 'm'
else:
self.length *= self.ft_to_m
self.unit_name = 'ft'
self.current_units = self.choose_units
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
TestIt = TestDialog()
# put the actual dialog up...
TestIt.configure_traits()
Use a notification as described here: http://code.enthought.com/projects/traits/docs/html/traits_user_manual/notification.html
Update in response to updated question:
Right, labels are not dynamically updated. Instead, make a text field that looks like a label, e.g. with:
label_text = String('Test length, English:')
Then display it in your View with something like:
Item("label_text", style='readonly', show_label=False),
You'll probably also want to use an HGroup nested inside your (V)Group, to position it to the left of your "length" display.
Then modify label_text inside your listener.

GtkToolbar: How to add Toolitem to toolbar using PyGObject

How can I add icons to a GtkToolbar using PyGObject?
I can create the toolbar and an icon without any problems:
self.toolbar = Gtk.Toolbar()
self.item = Gtk.ToolItem()
But adding the item to the toolbar doesn't seem to work like this (Found this in the PyGTK documentation):
self.toolbar.Container.add(self.item)
The solution is actually pretty simple:
self.button = Gtk.ToolButton(Gtk.STOCK_ABOUT)
self.toolbar.insert(self.button, 0)
User button instead of item and then choose an icon from this list: http://python-gtk-3-tutorial.readthedocs.org/en/latest/stock.html
Then use .inset with the object and the position (in this case 0, meaning the first item in the toolbar).

Menu or MenuButton with separate click handler

I'm looking for a widget like this.
http://ppt.cc/RPfL
Clicking "View" and triangle (drop down icon) need to perform two different functions.
Clicking the triangle opening the menu.
I tried creating 2 buttons to emulate, but the 2 buttons have extra space in between them.
How can I eliminate the space between buttons or, is there a convenient way to accomplish this?
thank you all!!
An IconMenuButton (which is a sub class of IconButton) will provide what you need.
Menu menu = new Menu();
MenuItem newItem = new MenuItem("New");
MenuItem openItem = new MenuItem("Open");
MenuItem saveItem = new MenuItem("Save");
MenuItem saveAsItem = new MenuItem("Save As");
menu.setItems(newItem, openItem, saveItem, saveAsItem);
IconMenuButton menuButton = new IconMenuButton("View", menu);
Also check SmartGWT samples I've given in my comment and RibbonBar sample.

set up the entry of a combobox (gtk)

How could I set up the text of a combobox without knowing its id? I have a combobox populated with a list of name ('Jack','Emily','Paul',...). By default, the combo is set on -1 but I want it to be set on "Paul".
Here is my code to declare and populate the combo with tuple (id,fabName) :
self.cmbFabricant = builder.get_object("cmbFabricant")
self.cmbFabricant.set_model(lstStore)
self.cmbFabricant.set_entry_text_column(1)
Now, I'd like to set the combobox on the item called "Paul". I thought I could write :
self.cmbFabricant.set_active_id('Paul')
I was wrong.
I could be wrong, but I think set_active_id is new in GTK+ 3, and PyGTK is GTK+ 2. If you want to use GTK+ 3, you have to switch to PyGObject.
But if you're stuck on PyGTK, you can easily work around it by doing something like this:
import gtk
def set_active_name(combobox, col, name):
liststore = combobox.get_model()
for i in xrange(len(liststore)):
row = liststore[i]
if row[col] == name:
combobox.set_active(i)
window = gtk.Window()
window.connect("destroy", gtk.main_quit)
liststore = gtk.ListStore(int, str)
liststore.append([0, 'Jack'])
liststore.append([1, 'Emily'])
liststore.append([2, 'Paul'])
combobox = gtk.ComboBox()
cell = gtk.CellRendererText()
combobox.pack_start(cell)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(liststore)
set_active_name(combobox, 1, 'Paul')
window.add(combobox)
window.show_all()
gtk.main()
I'm not sure if there is a more elegant/efficient way, but this works at least.