ListStore: Index ermitteln

Programmierung für GNOME und GTK+, GUI-Erstellung mit Glade.
Antworten
Benutzeravatar
MaXXLy
User
Beiträge: 24
Registriert: Sonntag 25. Mai 2008, 17:51

Moin Moin,

ich habe hier eine Listbox:

Code: Alles auswählen

	def List(self):
		"""create a new scrolled window."""
		scrolled_window = gtk.ScrolledWindow()
		scrolled_window.set_border_width(10)
		# set_policy(the horizontal scrollbar, the vertical scrollbar).
		scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
		# create a liststore with column to use as the model
		self.myListstore = gtk.ListStore(int, str, str)		
		# create the TreeView using liststore
		self.treeview = gtk.TreeView(self.myListstore)
                [...]
Diese Liste hat drei Spalten, die sortiert werden können. Mit einem Klick auf einen Eintrag wird weiterer Inhalt angezeigt. Wie komme ich an den Index der Zeilen?

Ich habe erst einemal eine versteckte Spalte durchnummeriert.:

Code: Alles auswählen

for key, val in self.ChannelList.iteritems():
	self.myListstore.append(key, '%s' % value1, '%s' % value2)
Frage an die Experten: Ist das so richtig oder kann mir das Object einen eindeutigen Index liefern?

M.[/code]
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Was spricht gegen einen `gtk.TreeIter`? Der ist eindeutig und zeigt immer noch auf dieselbe Zeile, auch wenn noch eine eingefügt wird, etc.
Benutzeravatar
MaXXLy
User
Beiträge: 24
Registriert: Sonntag 25. Mai 2008, 17:51

Irgendwie brauche ich eine Erleuchtung:

Ich habe nun Folgendes gemacht:

Code: Alles auswählen

		selection = self.treeview.get_selection()
		if selection.get_mode() == gtk.SELECTION_SINGLE:
			model, iter = selection.get_selected()
			print self.myListstore.get_path(iter)
Dieser Path wird aber nach dem Sortieren neu geschrieben. Und da ich diesen Index in einem Dict verwende, würde also auch das Klick-Resultat anders sein.

Wie mache ich das am Besten? Gibt es eine Methode, die dem Eintrag einen festen Index vergibt?

Danke für die Hilfe. M.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Du bekommst dann ganz einfach eine `gtk.TreeModelRow` mit ``model[iter]``. Und das ändert sich auch nicht, wenn die Sortierung geändert wird. ``model[iter]`` wird wieder dieselbe `gtk.TreeModelRow` zurückgeben.
Benutzeravatar
MaXXLy
User
Beiträge: 24
Registriert: Sonntag 25. Mai 2008, 17:51

Ich habe mal das Teil von allem Überflüsigem befreit und unten zitiert.
Mit meinem Weg ist es so:
Man markiert z.B. den emil und klickt: {4}
Dann sortieren der Liste alphabetisch.
Nun steht der emil an erster Stelle oben.
Klick auf emil: {0}

Wie kann ich die Reihen nach dem Füllen der Liste intern fest indexieren?

Danke für Deine Hilfe.

Mathias

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, time
import pygtk
pygtk.require('2.0')
import gtk, gobject

class MainWin(TvXmlParser):
	def __init__(self):
		self.myWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
		self.myListstore = gtk.ListStore(int, str, str)		
		self.treeview = gtk.TreeView(self.myListstore)
		self.treeview.connect("row-activated", self.Call_ListClick)
		
		col = {
			#0:['Nr',0], 
			1:['Time',1],
			2:['Title',2]}
			
		for key, val in col.iteritems():
			tvcolumn = gtk.TreeViewColumn(val[0])
			self.treeview.append_column(tvcolumn)
			cell = gtk.CellRendererText()
			tvcolumn.pack_start(cell, True)
			tvcolumn.set_attributes(cell, text=val[1])
			tvcolumn.set_sort_column_id(key)
		
		self.myListstore.append([0, 'a','anton'])
		self.myListstore.append([0, 'b','berta'])
		self.myListstore.append([0, 'c','conrad'])
		self.myListstore.append([0, 'd','dora'])
		self.myListstore.append([0, 'e','emil'])
		
		self.myWindow.add(self.treeview)

		self.myWindow.show_all()

	def Call_ListClick(self, *args):
		selection = self.treeview.get_selection()
		if selection.get_mode() == gtk.SELECTION_SINGLE:
			model, iter = selection.get_selected()
			print self.myListstore.get_path(iter)
			#print model.row(iter)
			if iter:
				val, val1, val2 = model.get(iter, 0, 1, 2)
				#print val, val1, val2
		return 0

if __name__ == "__main__":
	Win = MainWin()
	gtk.main()
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Ich verstehe das Problem gerade ehrlich gesagt nicht. Was genau willst du denn erreichen? Natürlich ändert sich der Pfad, wenn man umsortiert/neue Zeilen einfügt/whatever. Aber mit ``iter`` hast du doch einen eindeutigen Index. ``model.get(iter, 0, 1, 2)`` wird dir immer dasselbe zurückgeben. Füg doch mal

Code: Alles auswählen

gobject.timeout_add(
    5000,
    lambda model, iter_:
        sys.stdout.write('%s\n' % model.get_value(iter_, 2)),
    model, iter
)
beim Klickcode ein, klick auf einen Eintrag und sortiere danach um. Nach 5 Sekunden wird wieder der ausgewählte Eintrag ausgegeben, auch wenn sich der Pfad inzwischen geändert hat.
Benutzeravatar
MaXXLy
User
Beiträge: 24
Registriert: Sonntag 25. Mai 2008, 17:51

Eventuell habe ich ja auch schon einen Schuß :?:

Ich habe hier eine Menge Daten: Dict mit Überschriften und großem Text.
In dem Liststore sollen nur die Überschriften angezeigt werden.
Mit dem Klick auf einem Item soll dann der Rest angezeigt werden.

Irgendwie schaffe ich es nicht den Bezug zum Dict zu halten. Den Wert in der Liste finde ich immer, klar. Aber ich verliere die Position, die beim ersten Füllen bestand. Darum habe ich eine versteckte Spalte für den key des Dicts genommen.

Meine Frage ist das so die einzige Möglichkeit? Wie kann ich den Key an das Model_Row binden(schreiben)?

Der Hintergrund ist, ich möchte das GUI so strikt wie möglich von den Daten trennen.

M. der schon völlig konfus ist, aber dankbar für die Hilfe :shock:
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Naja, wenn man wirklich den Pfad später wieder haben will, den eine Zeile beim Befüllen hatte, könnte man ein `gtk.TreeModelSort` verwenden. ``self.treeview = gtk.TreeView(self.myListstore)`` müsstest du dann mit ``self.treeview = gtk.TreeView(gtk.TreeModelSort(self.myListstore))`` austauschen und im Klickcode bekommst du den Pfad dann mit

Code: Alles auswählen

# ...
model, iter = selection.get_selected()
print model.get_model().get_path(model.convert_iter_to_child_iter(None, iter))
(wobei model.get_model() ``self.myListstore`` zurückgibt).

Wenn das wirklich das ist, was du wolltest, willst du aber vllt auch eine Liste verwenden für die Daten, und kein dict.
Benutzeravatar
MaXXLy
User
Beiträge: 24
Registriert: Sonntag 25. Mai 2008, 17:51

Eben erst nach Hause; E-Mail-Check; sofort auf diese Forum; Dein Posting ausprobiert: Klappt!!!

:lol: :wink: :o :D :shock: :idea:

Das ist erstmal so wie ich es haben will.

So sind die Daten von der GUI vollständig getrennt.
Da ich die Daten selbst erstelle (XML) werde ich das auch in eine Liste packen.

Morgen werde ich das alles analysieren und dann hoffentlich auch begreifen.

Nochmals Danke

M.
Antworten