I have a Gtk.ComboBoxText that should be used as a trigger to activate a row in a Gtk.TreeView. I know how to trigger the combo box by activating the respective row in the tree view. But vice versa is beyond my scope. I learned that I need to pass Gtk.TreePath and Gtk.TreeViewColumn to the function row_activated(), but I don't know how to implement these correctly and where to put the row ID in my function self.combo_changed(). This is an example of the issue:
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(200, 100)
self.set_border_width(10)
self.grid = Gtk.Grid(row_spacing=10)
self.add(self.grid)
self.combo = Gtk.ComboBoxText()
self.combo.connect("changed", self.combo_changed)
self.grid.attach(self.combo, 0, 0, 1, 1)
self.liststore = Gtk.ListStore()
self.liststore.set_column_types([int, str])
self.treeview = Gtk.TreeView(self.liststore)
self.treeview.set_activate_on_single_click(True)
self.treeview.connect('row-activated', self.list_changed)
self.grid.attach(self.treeview, 0, 1, 1, 1)
cols = ["ID", "Animal"]
self.treeviewcolumn = []
self.cellrenderertext = []
for i in range(len(cols)):
self.cellrenderertext.append(Gtk.CellRendererText())
self.treeviewcolumn.append(Gtk.TreeViewColumn(cols[i]))
self.treeviewcolumn[i].pack_start(self.cellrenderertext[i], True)
self.treeviewcolumn[i].add_attribute(self.cellrenderertext[i], "text", i)
self.treeview.append_column(self.treeviewcolumn[i])
animals = ["Dog", "Cat", "Mouse"]
self.rowiter = []
for i in range(len(animals)):
self.combo.append_text(animals[i])
self.rowiter.append([self.liststore.append([i, animals[i]])])
self.combo.set_active(0)
def list_changed(self, widget, row, data2):
self.combo.set_active(int(row.to_string()))
def combo_changed(self, widget):
print(widget.get_active()) # the ID of the requested row
#self.treeview.row_activated(Gtk.TreePath(), Gtk.TreeViewColumn())
def quit_window(self, widget, data=None):
Gtk.main_quit()
win = MainWindow()
win.show_all()
win.connect("delete-event", win.quit_window)
Gtk.main()
I discovered that I also need Gtk.TreeView.set_cursor() to achieve my goal:
def combo_changed(self, widget):
row = widget.get_active() # the ID of the requested row
print(row)
self.treeview.row_activated(Gtk.TreePath(row), Gtk.TreeViewColumn(None))
self.treeview.set_cursor(Gtk.TreePath(row))
Related
I am teaching myself Python Gtk+3 using the readthedocs tutorial. I'm currently working on drag and drop and want to create a TreeView where every line is dragable. To do this, my code reads in a list of telecommands and puts them in a TreeView. This TreeView works and I can drag the single lines around. When I drop them into the designated drop area however, nothing happens.
My current goal is for the program to just print the text "Received data", whenever I drop something. Later on, I want the program to print out the single commands, that have been dropped.
My code looks as follows(I followed this example):
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
from csv import reader
# get data from file and format it
with open ("TC_list.csv", "r") as read_command_list:
csv_reader = reader(read_command_list)
list_of_commands = list(csv_reader)
list_header = list_of_commands.pop(0)
for command in list_of_commands:
command[0] = int(command[0])
command[1] = int(command[1])
DRAG_ACTION = Gdk.DragAction.COPY
class DragDropWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Drag and Drop Demo")
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
self.grid.set_size_request(1200, 1000)
self.listview = DragSourceListView()
self.drop_area = DropArea()
self.grid.attach(self.listview, 0, 0, 1, 1)
self.grid.attach_next_to(self.drop_area, self.listview, \
Gtk.PositionType.BOTTOM, 1, 1)
class DragSourceListView(Gtk.Grid):
def __init__(self):
Gtk.Grid.__init__(self)
# Creating ListStore model
self.telecommand_liststore = Gtk.ListStore(int, int, str, str)
for telecommand_ref in list_of_commands:
self.telecommand_liststore.append(list(telecommand_ref))
self.current_filter_telecommand = None
# Creating the filter, feeding it with the liststore model
self.telecommand_filter = self.telecommand_liststore.filter_new()
# setting the filter function
self.telecommand_filter.set_visible_func(self.telecommand_filter_func)
# creating the treeview, making it use the filter a model, adding columns
self.treeview = Gtk.TreeView.new_with_model(Gtk.TreeModelSort(self.telecommand_filter))
for i, column_title in enumerate(list_header):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
column.set_sort_column_id(i)
self.treeview.append_column(column)
# set up drag-source
self.treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [], DRAG_ACTION)
self.treeview.connect("drag-data-get", self.on_drag_data_get)
# setting up layout, treeview in scrollwindow
self.scrollable_treelist = Gtk.ScrolledWindow()
self.scrollable_treelist.set_vexpand(True)
self.scrollable_treelist.set_hexpand(True)
self.attach(self.scrollable_treelist, 0, 1, 8, 10)
self.scrollable_treelist.add(self.treeview)
def telecommand_filter_func(self, model, iter, data):
if (
self.current_filter_telecommand is None
or self.current_filter_telecommand == "None"
):
return True
else:
return model[iter][0] == self.current_filter_telecommand
def on_drag_data_get(self, widget, drag_context, dat, info, time):
selected_tc = self.get_selected_items()[0]
selected_iter = self.get_model().get_iter(selected_tc)
class DropArea(Gtk.Label):
def __init__(self):
Gtk.Label.__init__(self)
self.set_label("Drop Area")
self.drag_dest_set(Gtk.DestDefaults.ALL, [], DRAG_ACTION)
self.connect("drag-data-received", self.on_drag_data_received)
def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
print("Received data")
win = DragDropWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
What am I overlooking here? Why doesn't the drop-area do anything?
Try to set gtk_tree_view_set_reorderable to True.
So the below code is part of a bigger project but in general, I have a QTableWidget which is populated from a database. One of the items is a combobox which when the user selects a milestone option from the combobox I want to be able to know which row and column the combo box that was select is in so I can then apply a fixed rate to the value of a cell in the same row. All I need help on is how to track which cell (row, column) the combo box that was selected is in.
Please note im using other tabs that are not shown and is why my code is setup the way it is. I found some other help but am not a very experience python programmer so I got stuck.
#!/usr/local/bin/python
# -*- coding: latin9 -*-
import sys, os , random
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT
import time
import json
import openpyxl
import Lists
class CashflowTab(QtGui.QDialog):
'''
Parent for all tab widgets of the REPO GUI
'''
def __init__(self, parent = None):
super(CashflowTab, self).__init__()
if parent != None:
self.setParent(parent)
self.initUI()
self.loadSettings()
def loadSettings(self):
'''
read settings and read db
'''
fh = open('settings.json')
self.settings = json.load(fh)
fh.close()
#load db
dbpath = self.settings['dbpath']
self.db = Lists.SQLiteHandler(dbpath)
self.repo = Lists.WCNList('ROSQL')
try:
self.db.read(self.repo)
except:
pass
class WCNSelectTab(CashflowTab):
'''
Window for WCN selection
'''
def __init__(self, parent = None):
super(WCNSelectTab, self).__init__(parent)
if parent != None:
self.setParent(parent)
def initUI(self):
global wbsitem, WCNSelectTab_object, linequerycheck
linequerycheck = 'False'
wbsitem = 'null'
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("cleanlooks"))
gbox = QtGui.QGridLayout(self)
self.projectlist = QtGui.QTableWidget()
self.projectlist.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
#self.projectlist.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.projectlist.setColumnCount(3)
self.projectlist.setHorizontalHeaderLabels(QtCore.QStringList(['WBS','Service','Milestone']))
self.projectlist.setColumnWidth(0, 100)
self.projectlist.setColumnWidth(1, 100)
self.projectlist.setColumnWidth(2, 150)
gbox.addWidget(self.projectlist,5,0,3,6)
self.getAwardBudget()
def getAwardBudget(self):
global wbs_details
wbs_details = []
wbs_details.append(["123", "Service 1"])
wbs_details.append(["456", "Service 2"])
print wbs_details
self.projectlist.setRowCount(len(wbs_details))
for n,item in enumerate(wbs_details):
qitem = QtGui.QTableWidgetItem(item[0])
self.projectlist.setItem(n, 0, qitem)
qitem = QtGui.QTableWidgetItem(item[1])
self.projectlist.setItem(n, 1, qitem)
milestone_options = ["Award","Mobilization","Survey"]
milestonecombo = QtGui.QComboBox()
for t in milestone_options:
milestonecombo.addItem(t)
milestonecombo.setFixedWidth(150)
self.projectlist.setCellWidget(n, 2, milestonecombo)
class RepoGUI(QtGui.QMainWindow):
'''
Main Widget for REPO helper
'''
def __init__(self):
super(RepoGUI, self).__init__()
#self.mode = mode
self.initUI()
def initUI(self):
global approval, approval_names, username, approval_names
self.tabs = QtGui.QTabWidget()
self.setCentralWidget(self.tabs)
self.tabs.setAutoFillBackground(1)
fh = open('settings.json')
settings = json.load(fh)
fh.close()
if settings['WCNsubmit'] == 1:
self.tabs.addTab(WCNSelectTab(), 'WCN Creation')
self.setWindowTitle('Work Completion Notification')
self.setGeometry(300, 150, 1400, 800)
self.setStyleSheet('font-size: %ipt' %settings['fontsize'])
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = RepoGUI()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
A possible solution is to use indexAt() since the position of the QComboBox is relative to the viewport(), but to obtain the QComboBox that was selected we use sender().
for n,item in enumerate(wbs_details):
qitem = QtGui.QTableWidgetItem(item[0])
self.projectlist.setItem(n, 0, qitem)
qitem = QtGui.QTableWidgetItem(item[1])
self.projectlist.setItem(n, 1, qitem)
milestone_options = ["Award","Mobilization","Survey"]
milestonecombo = QtGui.QComboBox()
milestonecombo.addItems(milestone_options)
milestonecombo.setFixedWidth(150)
milestonecombo.currentIndexChanged[str].connect(self.onCurrentIndexChanged)
self.projectlist.setCellWidget(n, 2, milestonecombo)
def onCurrentIndexChanged(self, text):
combobox = self.sender()
ix = self.projectlist.indexAt(combobox.pos())
print(ix.row(), ix.column(), text)
Another possible solution is to use the property:
for n,item in enumerate(wbs_details):
qitem = QtGui.QTableWidgetItem(item[0])
self.projectlist.setItem(n, 0, qitem)
qitem = QtGui.QTableWidgetItem(item[1])
self.projectlist.setItem(n, 1, qitem)
milestone_options = ["Award","Mobilization","Survey"]
milestonecombo = QtGui.QComboBox()
milestonecombo.addItems(milestone_options)
milestonecombo.setFixedWidth(150)
milestonecombo.setProperty("row", n)
milestonecombo.setProperty("column", 1)
milestonecombo.currentIndexChanged[str].connect(self.onCurrentIndexChanged)
self.projectlist.setCellWidget(n, 2, milestonecombo)
def onCurrentIndexChanged(self, text):
combobox = self.sender()
r = combobox.property("row").toPyObject()
c = combobox.property("column").toPyObject()
print(r, c, text)
I have created a custom matplotlib toolbar, and I'm working on the functions associated with the custom toolbar's buttons. One of the buttons functions will (eventually) return a list position that best represents a user's selected position from a plot. I was having a bit of difficulty making this work in my mind, so I made a simple example (trying to avoid using globals) where a label not associated with the toolbar is updated when the toolbar button is pressed.
class TrackPlotToolbar(NavigationToolbar2TkAgg):
toolitems = [t for t in NavigationToolbar2TkAgg.toolitems if
t[0] in ('Home', 'Pan', 'Zoom', 'Save')]
toolitems.append(('Trace', 'Trace Track Position', 'Trace', 'Trace_old'))
def __init__(self, plotCanvas, frame):
self.TraceListOld = []
self.TraceListNew = []
NavigationToolbar2TkAgg.__init__(self, plotCanvas, frame)
def set_message(self, msg):
pass
def Trace_old(self):
gui.infoLabel.text = "abrakadabra"
gui.infoLabel.update()
return 1
class gui(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.grid()
self.parent = parent
self.infoLabel = Label(master = self, text = 'magic')
self.initUI()
def initUI(self):
TestPlot = FigureCanvasTkAgg(TestFig, self)
TestPlot.get_tk_widget().grid(column = 0,\
row = 0, columnspan = 3, rowspan = 5)
TestFrame = Frame(self)
TestFrame.grid(column = 2, row =6, columnspan = 3)
shockToolbar = TrackPlotToolbar(TestPlot,TestFrame)
shockToolbar.update()
self.infoLabel.grid(column = 2, row = 7)
def main():
root = Tk()
app = gui(root)
root.mainloop()
if __name__ == '__main__':
main()
Am I taking the wrong approach? Is it possible to inquire for new data on an event associated with a class inside of the parent class?
probably I'm less than a newbie in both python and GTK. Here my problem:
I've created a class to display a windows with a search bar and a treeview.
I fill the tree reading from an SQLITEDB.
Fine.
I'd like to use the search bar in order to select an item in the treeview (so performing, a db search and fill the treeview with the result)
I'm blocked on the callback since I cannot understand how to pass the user inserted data to a specific function.
Below some lines from my (STUPID) code.
class SecondWin:
def __init__(self):
self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.win.connect("delete_event", self.delete_event)
self.win.set_title("Gmail Phonebook")
self.win.set_size_request(600, 300) #Larghez1za, Altezza
self.win.set_border_width(8)
self.win.set_position(gtk.WIN_POS_CENTER)
self.win.connect("destroy", self.destroy)
self.table = gtk.Table(8, 8,True)
self.cerca_bottone = gtk.Button("Cerca")
self.cerca_bottone.set_size_request(70, 30) #Larghezza, Altezza
self.cerca_bottone.connect( "clicked", self.cercainrubrica) #Call back sul bottone
self.table.attach(self.cerca_bottone, 0, 1, 0, 1,gtk.SHRINK,gtk.SHRINK)
# Search BAR
self.hbox = gtk.HBox()
self.entry = gtk.Entry(30)
self.entry.connect("activate", self.cercainrubrica) #call back su enter
self.hbox.pack_end(self.entry)
self.table.attach(self.hbox, 1, 8, 0, 1,gtk.EXPAND|gtk.FILL|gtk.SHRINK,
gtk.EXPAND|gtk.FILL|gtk.SHRINK,0,0)
self.vbox = gtk.VBox(False, 8)
self.sw = gtk.ScrolledWindow()
self.sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.vbox.pack_start(self.sw, True, True, 0)
self.table.attach(self.vbox, 1, 8, 1, 9,gtk.EXPAND|gtk.FILL|gtk.SHRINK,
gtk.EXPAND|gtk.FILL|gtk.SHRINK,10,10)
rubrica=mydb.find_record_complex("%", colonne_test[0])
store = self.create_model(rubrica) #THIS WORK FINE DISPLAYING THE SELECTION
HERE MY FUNCION
self.cercainrubrica ??
treeView=gtk.TreeView(store)
treeView.connect("row-activated", self.on_activated)
treeView.set_rules_hint(True)
self.sw.add(treeView)
self.create_columns(treeView,nomi_colonne)
self.statusbar = gtk.Statusbar()
self.win.add(self.table)
self.win.show_all()
THIS IS MY CALL BACK
def cercainrubrica( self, w, data=None):
name = self.entry.get_text()
capperi=mydb.find_record_complex(name, colonne_test[0])
store = self.create_model(capperi)
return store
def delete_event(self, widget, event, data=None):
return gtk.FALSE
def destroy(self, widget, data=None):
return gtk.main_quit()
def main(self):
gtk.main()
def create_model(self,records):
store = gtk.ListStore(str, str, str,str)
for record in records:
store.append([record[1], record[2], record[3],record[4]])
return store
def create_columns(self, treeView,intestazione_colonne):
i = 0
for nomecolonna in intestazione_colonne:
rendererText = gtk.CellRendererText()
column = gtk.TreeViewColumn(intestazione_colonne[i], rendererText, text=i)
column.set_sort_column_id(i)
treeView.append_column(column)
i += 1
def on_activated(self, widget, row, col):
model = widget.get_model()
text = model[row][0] + ", " + model[row][1] + ", " + model[row][2]
self.statusbar.push(0, text)
if __name__ == "__main__":
second = SecondWin()
second.main()
ANY HELP IS REALLY APPRECIATED
Not 100% sure what you want to do but if you want to filter what the treeview is showing based on the entered text, you should take a look at GtkTreeModelFilter. You can use it as a TreeModel and set your own VisibleFunc that decides if a row should be visible or not based on the entered text. When the text changes, just call refilter(): that will call VisibleFunc() for every row.
Sorry for not having a python example or docs for you, I hope that still helps...
hey I'm new and I've a problem
I'm trying to create a TreeView with a ListStore. The ListStore should get a list from another class but it seems I can't fill my ListStore.
so here's the code
TreeView and ListStore:
labelDB = gtk.Label('Database')
self.storeDB = gtk.ListStore(str, str, int, str)
rentexDB = gtk.CellRendererText()
colDB1 = gtk.TreeViewColumn('Name', rentexDB)
colDB2 = gtk.TreeViewColumn('URL', rentexDB)
colDB3 = gtk.TreeViewColumn('Bitrate', rentexDB)
colDB4 = gtk.TreeViewColumn('Format', rentexDB)
self.fillStore()
pageDB = gtk.TreeView(model=self.storeDB)
pageDB.append_column(colDB1)
pageDB.append_column(colDB2)
pageDB.append_column(colDB3)
pageDB.append_column(colDB4)
showData.append_page(pageDB, labelDB)
and the fillStore:
def fillStore(self):
dataInStore = self.record.useDB()
if dataInStore is not None:
self.storeDB.clear()
for row in dataInStore:
#print row
self.storeDB.append(row)
return self.storeDB
when I print the row's I can see the List's I want to store in my ListStore
but the ListStore is always empty
I hope someone can help me, please
below is a demo app:
#!/usr/bin/env python3
from gi.repository import Gtk
class Demo:
def __init__(self):
self.window = Gtk.Window()
self.window.set_default_size(640, 480)
self.window.connect('delete-event', self.on_app_exit)
scrolledwindow = Gtk.ScrolledWindow()
self.window.add(scrolledwindow)
self.liststore = Gtk.ListStore(str, str, int, str)
# You need to use self.fillStore() instead.
self.liststore.append(['Debian', 'i386', 0, 'ok'])
self.liststore.append(['Fedora', 'amd64', 1, 'ok'])
self.liststore.append(['Ubuntu', 'i386', 2, 'ok'])
treeview = Gtk.TreeView(model=self.liststore)
scrolledwindow.add(treeview)
names = ('Name', 'URL', 'Bitrate', 'Format')
for i in range(4):
renderer_text = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(names[i], renderer_text, text=i)
treeview.append_column(column)
def fillStore(self):
pass
def run(self):
self.window.show_all()
Gtk.main()
def on_app_exit(self, widget, event=None):
Gtk.main_quit()
if __name__ == '__main__':
demo = Demo()
demo.run()