I have to create a GUI in maya python wherein I have to use Sql query to get
projectname,os,projectid , path . For example in my code if Projectname selected is "Abc" then os,projectid and path should be selected as per the selected projectname. how to do this??
I got the projectname but i cannot get other parameters
import os,mysql.connector as mc , platform
cmds.window(title='Test Window')
name = []
id = []
Os = []
path = []
wpath = []
# Query for getting various projects from db
cursor = db.cursor()
#selecting projectname
ans = cursor.fetchall()
cursor.close()
def projid(name):
#selecting project id
pid = cursor.fetchone()
print "out"
print pid
def Getprojid(z):
global pname
pname = cmds.optionMenu(z , query=True,value = True)
for ans1 in ans:
name .append(ans1[0])
cmds.columnLayout()
polygonSelectMenu = cmds.optionMenu(w = 250, h = 30, label = "Project
Selection:")
for proj in name:
cmds.menuItem(label = proj)
cmds.button(label='click me Select project ',
command='printTxtField(polygonSelectMenu)')
cmds.showWindow()
Since you are new to Python Maya Gui, you have to take care of few things while writing tools which involved ui interaction.
Keep your UI module and Core module(The core functionality part or the data layer) separate.
If you have any Database association, keep the DB module separate, which should ideally read, write or update the database.
If possible you can also keep an interaction layer or module for integrating the core and ui module along with db layer.
There can be more granular or organized designs, but as for starting this will help you to get the things done.
Given below is an example from your requirement.
Here I am assuming your project and its relevant details are coming from database or any other resources.
#=========================================================================#
# db code:
#=========================================================================#
# This module can have your own implementation. I am just writing some example code.
def get_projects_data(*args, **kwargs):
""" This should return all the records of the project table from your db.
For filters you can pass them through kwargs.
"""
return [{'id': 1021, 'name': 'Abc', 'os': 'some os', 'path': 'some path'},
{'id': 1022, 'name': 'Def', 'os': 'some other os', 'path': 'some other path'}]
#=========================================================================#
# Ui Code:
#=========================================================================#
import maya.cmds as cmds
class ProjectUI(object):
_name = 'ProjectManager'
_title = 'Project Manager'
def __init__(self, project_data=None):
self.project_data = project_data
self.win = None
# Create the UI
self.create_ui()
# Try to populate the projects
self.populate_projects()
# Force update the details for first time
self.update_project_details()
def create_ui(self):
"""This will create required UI components
"""
# First check if the ui exists, then close it
self.close()
# Now thw create the window
self.win = cmds.window(self.name, title=self.title)
# Creat a column layout with adjustable True and row spacing to 5
cmds.columnLayout(adj=True, rs=5)
# Create project option menu and add a change commang to trigger while
# you chnage the projects from the option menu.
self.project_om = cmds.optionMenu(
label='Projects', ChangeCommand=self.update_project_details)
# Create required text fields
self.project_id_tf = cmds.textFieldGrp(label='Id', editable=False)
self.project_path_tf = cmds.textFieldGrp(label='Path', editable=False)
self.project_os_tf = cmds.textFieldGrp(label='OS', editable=False)
def populate_projects(self):
"""This should populate all the available projects in poject option menu.
"""
# First check if we have any project data in hand. If not then we should
# exit right away.
if not self.project_data:
print('No project data found for populatin projects')
retturn
for data in project_data:
prject = data.get('name')
menuItem(label=project, parent=self.project_om)
def update_project_details(self, project=''):
"""This should update all other project details in UI and must me
triggered while changing projects from poject option menu.
"""
if not self.project_data:
retturn
if not project:
project = cmds.optionMenu(self.project_om, q=True, value=True)
project_details = None
for data in self.project_data:
if project == data.get('name'):
project_details = data
break
if not project_details:
print('No project details found for %s' % project)
return
proj_id = project_details.get('id')
proj_path = project_details.get('path')
proj_os = project_details.get('os')
cmds.textFieldGrp(self.project_id_tf, e=True, text='%s' % proj_id)
cmds.textFieldGrp(self.project_path_tf, e=True, text=proj_path)
cmds.textFieldGrp(self.project_os_tf, e=True, text=proj_os)
def show(self):
"""Just show the UI if its created ever.
"""
if self.win:
cmds.showWindow(self.win)
def close(self):
"""For deleting the UI if exists
"""
if cmds.window(self._name, query=True, exists=True):
cmds.deleteUi(self.name, window=True)
#=========================================================================#
# Integration Code:
#=========================================================================#
def main():
# First fetch the data
data = get_projects_data()
if not data:
print('No project data fetched.')
return
win = ProjectUI(project_data=data)
win.show()
# Return the win just if you want an pointer to same
return win
# Now just call the main method, whenever required
main()
The above code snippet is just an example. This is not tested inside maya. But I hope this will give you a starting point. Again if are not familiar with classes, you can do the same thing procedural way, by passing args. I will highly suggest PySide or PyQt along with PyMel for robust and efficient Ui Tools.
Related
I do have a problem while updating my content on-demand.
My scenario: I want to create a GUI which stores information about some products and it should be displayed via a scroll are. This is working fine, but when I want to update the information like the quantity of my item, the GUI or the layout of my QVBoxLayout does not update the new information on the screen.
My code for the update function:
#pyqtSlot(GroupContent)
def _updateData(self, box: GroupContent) -> None:
prompt = UpdatePrompt(self._conn, box)
prompt.exec()
amount = self._top_layout.count()
for i in range(amount):
tmp = self._top_layout.itemAt(i).widget()
if tmp.id != box.id:
continue
tmp.setTitle(box.title)
tmp.lblPrice.setText(str(box.price))
tmp.lblQuantity.setText(str(box.quantity))
The param box does already get the updated information from a QDialog.
The self._top_layout variable will be created with self._top_layout = QVBoxLayout().
I already tried to call update on the Mainwindow and also on the top layout.
Also tried directly accessing the widget with self._top_layout.itemAt(i).widget().setTitle('test') for example.
If this information is necessary, here is my function to dynamic generate the groupboxes:
def _populate(self, insert: Boolean = False) -> None:
data = self._getDBData(insert)
for row in data:
group_box = GroupContent()
group_box.storage_id.connect(self._updateData)
group_box.id = row.storage_id
group_box.title = row.name
group_box.price = row.price
group_box.quantity = row.quantity
group_box.image = row.image
self._top_layout.addWidget(group_box)
When a "choose files" dialog is displayed I want to pre-select files in a project which are already configured as being "part of" that project, so the user can select new files OR unselect existing (i.e. previously chosen) files.
This answer suggests multiple selection should be possible.
For this MRE, please make 3 files and put them in a suitable ref_dir:
from PyQt5 import QtWidgets
import sys
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.button = QtWidgets.QPushButton('Test', self)
self.button.clicked.connect(self.handle_button)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
def handle_button(self):
options = QtWidgets.QFileDialog.Options()
options |= QtWidgets.QFileDialog.DontUseNativeDialog
ref_dir = 'D:\\temp'
files_list = ['file1.txt', 'file2.txt', 'file3.txt']
fd = QtWidgets.QFileDialog(None, 'Choose project files', ref_dir, '(*.txt)')
fd.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
fd.setOptions(options)
# fd.setVisible(True)
for file in files_list:
print(f'selecting file |{file}|')
fd.selectFile(file)
string_list = fd.exec()
print(f'string list {string_list}')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Unfortunately, despite ExistingFiles having been chosen as the file mode, I find that it is only the last file selected which has the selection... but I want all three to be selected when the dialog is displayed.
I tried experimenting with setVisible to see whether the multiple selection could be achieved somehow after the dialog is displayed, but this didn't work.
Since a non-native file dialog is being used, we can access its child widgets to control its behavior.
At first I thought about using the selection model of the item views, but this won't update the line edit, which is responsible of checking if the files exist and enabling the Ok button in that case; considering this, the obvious solution is to directly update the line edit instead:
def handle_button(self):
# ...
existing = []
for file in files_list:
if fd.directory().exists(file):
existing.append('"{}"'.format(file))
lineEdit = fd.findChild(QtWidgets.QLineEdit, 'fileNameEdit')
lineEdit.setText(' '.join(existing))
if fd.exec():
print('string list {}'.format(fd.selectedFiles()))
The only drawback of this approach is that the fileSelected and filesSelected signals are not sent.
Musicamante's answer was very, very helpful, in particular showing that the selection is in fact triggered by filling the QLE with path strings.
But in fact there is a fatal flaw when the purpose is as I have stated: unfortunately, if you try to deselect the final selected file in a directory, actually this name is not then removed from the QLE. And in fact, if the QLE is set to blank this disables the "Choose" button. All this is by design: the function of a QFileDialog is either to "open" or to "save", not to "modify".
But I did find a solution, which involves finding the QListView which lists the files in the directory, and then using a signal on its selection model.
Another thing this caters for is what happens when you change directory: obviously, you then want the selection to be updated on the basis of the project's files as found (or not found) inside that directory. I've in fact changed the text of the "choose" button to show that "modification" is the name of the game.
fd = QtWidgets.QFileDialog(app.get_main_window(), 'Modify project files', start_directory, '(*.docx)')
fd.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
fd.setViewMode(QtWidgets.QFileDialog.List)
fd.setLabelText(QtWidgets.QFileDialog.Reject, '&Cancel')
fd.setLabelText(QtWidgets.QFileDialog.Accept, '&Modify')
fd.setOptions(options)
file_name_line_edit = fd.findChild(QtWidgets.QLineEdit, 'fileNameEdit')
list_view = fd.findChild(QtWidgets.QListView, 'listView')
# utility to cope with all permutations of backslashes and forward slashes in path strings:
def split_file_path_str(path_str):
dir_path_str, filename = ntpath.split(path_str)
return dir_path_str, (filename or ntpath.basename(dir_path_str))
fd.displayed_dir = None
sel_model = list_view.selectionModel()
def sel_changed():
if not fd.displayed_dir:
return
selected_file_paths_in_shown_dir = []
sel_col_0s = sel_model.selectedRows()
for sel_col_0 in sel_col_0s:
file_path_str = os.path.join(fd.displayed_dir, sel_col_0.data())
selected_file_paths_in_shown_dir.append(file_path_str)
already_included = file_path_str in self.files_list
if not already_included:
fd.project_files_in_shown_dir.append(file_path_str)
# now find if there are any project files which are now NOT selected
for project_file_path_str in fd.project_files_in_shown_dir:
if project_file_path_str not in selected_file_paths_in_shown_dir:
fd.project_files_in_shown_dir.remove(project_file_path_str)
sel_model.selectionChanged.connect(sel_changed)
def file_dlg_dir_entered(displayed_dir):
displayed_dir = os.path.normpath(displayed_dir)
# this is set to None to prevent unwanted selection processing triggered by setText(...) below
fd.displayed_dir = None
fd.project_files_in_shown_dir = []
existing = []
for file_path_str in self.files_list:
dir_path_str, filename = split_file_path_str(file_path_str)
if dir_path_str == displayed_dir:
existing.append(f'"{file_path_str}"')
fd.project_files_in_shown_dir.append(file_path_str)
file_name_line_edit.setText(' '.join(existing))
fd.displayed_dir = displayed_dir
fd.directoryEntered.connect(file_dlg_dir_entered)
# set the initially displayed directory...
file_dlg_dir_entered(start_directory)
if fd.exec():
# for each file, if not present in self.files_list, add to files list and make self dirty
for project_file_in_shown_dir in fd.project_files_in_shown_dir:
if project_file_in_shown_dir not in self.files_list:
self.files_list.append(project_file_in_shown_dir)
# also add to list widget...
app.get_main_window().ui.files_list.addItem(project_file_in_shown_dir)
if not self.is_dirty():
self.toggle_dirty()
# but we also have to make sure that a file has not been UNselected...
docx_files_in_start_dir = [f for f in os.listdir(fd.displayed_dir) if os.path.isfile(os.path.join(fd.displayed_dir, f)) and os.path.splitext(f)[1] == '.docx' ]
for docx_file_in_start_dir in docx_files_in_start_dir:
docx_file_path_str = os.path.join(fd.displayed_dir, docx_file_in_start_dir)
if docx_file_path_str in self.files_list and docx_file_path_str not in fd.project_files_in_shown_dir:
self.files_list.remove(docx_file_path_str)
list_widget = app.get_main_window().ui.files_list
item_for_removal = list_widget.findItems(docx_file_path_str, QtCore.Qt.MatchExactly)[0]
list_widget.takeItem(list_widget.row(item_for_removal))
if not self.is_dirty():
self.toggle_dirty()
After a few hours of playing around, here's a pretty good way to programatically pre-select multiple files in a QFileDialog:
from pathlib import Path
from PyQt5.QtCore import QItemSelectionModel
from PyQt5.QtWidgets import QFileDialog, QListView
p_files = Path('/path/to/your/files')
dlg = QFileDialog(
directory=str(p_files),
options=QFileDialog.DontUseNativeDialog)
# get QListView which controls item selection
file_view = dlg.findChild(QListView, 'listView')
# filter files which we want to select based on any condition (eg only .txt files)
# anything will work here as long as you get a list of Path objects or just str filepaths
sel_files = [p for p in p_files.iterdir() if p.suffix == '.txt']
# get selection model (QItemSelectionModel)
sel_model = file_view.selectionModel()
for p in sel_files:
# get idx (QModelIndex) from model() (QFileSystemModel) using str of Path obj
idx = sel_model.model().index(str(p))
# set the active selection using each QModelIndex
# IMPORTANT - need to include the selection type
# see dir(QItemSelectionModel) for all options
sel_model.select(idx, QItemSelectionModel.Select | QItemSelectionModel.Rows)
dlg.exec_()
dlg.selectedFiles()
>>> ['list.txt', 'of.txt', 'selected.txt', 'files.txt']
Please be kind. This is my first question. I have included a minimum listing that illustrates the problem.
from PyQt5 import QtWidgets, QtCore, QtGui, uic, QtSql
from PyQt5.QtCore import Qt
qtCreatorFile = "QuotesGui.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class QuotesUI(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, model):
QtWidgets.QMainWindow.__init__(self)
uic.loadUi(qtCreatorFile,self)
self.setupUi(self)
self.model = model # View owns the model
self.tableView.setModel(self.model._formModel)
self.setWidgetMapping() # Map model to view widgets
authorSRD = QtSql.QSqlRelationalDelegate(self.authorComboBox)
self.authorComboBox.setModel(self.model._authorModel)
self.authorComboBox.setItemDelegate(authorSRD)
self.authorComboBox.setModelColumn(
self.model._formModel.fieldIndex("authorName"))
citationSRD = QtSql.QSqlRelationalDelegate(self.citationComboBox)
self.citationComboBox.setModel(self.model._citationModel)
self.citationComboBox.setItemDelegate(citationSRD)
self.citationComboBox.setModelColumn(
self.model._formModel.fieldIndex("citationText"))
self.mainMapper.toFirst()
self._updateButtons(0) # To disable the previous button at start up
self.saveBtn.setEnabled(False) # Since we can't edit, we can't save
self._connectSignals(self.model)
def setWidgetMapping(self):
self.mainMapper = QtWidgets.QDataWidgetMapper(self)
self.mainMapper.setModel(self.model._formModel)
self.mainMapper.setItemDelegate(QtSql.QSqlRelationalDelegate(self))
self.mainMapper.addMapping(self.authorComboBox,
self.model._formModel.fieldIndex("authorName"))
self.mainMapper.addMapping(self.citationComboBox,
self.model._formModel.fieldIndex("citationText"))
self.mainMapper.addMapping(self.quoteText,
self.model._formModel.fieldIndex("quoteText"))
def _connectSignals(self, model):
self.lastBtn.clicked.connect(self.mainMapper.toLast)
self.nextBtn.clicked.connect(self.mainMapper.toNext)
self.prevBtn.clicked.connect(self.mainMapper.toPrevious)
self.firstBtn.clicked.connect(self.mainMapper.toFirst)
self.mainMapper.currentIndexChanged.connect(
self._updateButtons)
def _updateButtons(self, row):
self.firstBtn.setEnabled(row > 0)
self.prevBtn.setEnabled(row > 0)
self.nextBtn.setEnabled(row < self.model._formModel.rowCount() - 1)
self.lastBtn.setEnabled(row < self.model._formModel.rowCount() - 1)
class QuoteModel():
def __init__(self, data):
# Make a database connection
self.db = self.createConnection(data)
# set models
self._setFormModel()
self._setAuthorComboTableLink()
self._setCitationComboTableLink()
# Connect signals
self._connectSignals()
# Define a model for the form
def _setFormModel(self):
self._formModel = QtSql.QSqlRelationalTableModel(
parent = None, db = self.db)
self._formModel.setEditStrategy(
QtSql.QSqlTableModel.OnManualSubmit)
self._formModel.setTable("Quote")
authorIdx = self._formModel.fieldIndex("authorId")
citationIdx = self._formModel.fieldIndex("citationId")
self._formModel.setJoinMode(1) # Left Join
self._formModel.setRelation(authorIdx, QtSql.QSqlRelation(
"Author", "authorId", "authorName"))
self._formModel.setRelation(citationIdx, QtSql.QSqlRelation(
"Citation", "citationId", "citationText"))
self._formModel.select()
# Define models and link tables for the two comboboxes
def _setAuthorComboTableLink(self):
self._authorModel = QtSql.QSqlTableModel(
parent = None, db = self.db)
self._authorModel.setTable("Author")
self._authorModel.setEditStrategy(
QtSql.QSqlTableModel.OnManualSubmit)
self._authorModel.select()
self._authorModel.sort(1,Qt.AscendingOrder)
def _setCitationComboTableLink(self):
self._citationModel = QtSql.QSqlTableModel(
parent = None, db = self.db)
self._citationModel.setTable("Citation")
self._citationModel.setEditStrategy(
QtSql.QSqlTableModel.OnManualSubmit)
self._citationModel.select()
self._citationModel.sort(1,Qt.AscendingOrder)
def _newData(self):
print('in _newData')
def _connectSignals(self):
self._authorModel.rowsInserted.connect(self._newData)
#######################################################
# A function to connect to a named database
def createConnection(self,dbfile):
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName(dbfile)
db.open()
if not db.open():
QtWidgets.QMessageBox.critical(
None, QtWidgets.qApp.tr("Cannot open database"),
QtWidgets.qApp.tr("Unable to establish a database connection.\n"),
QtWidgets.QMessageBox.Cancel,
)
return False
return db
dbFile = "Quotations.db"
if __name__=='__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
m = QuoteModel(dbFile)
w = QuotesUI(m)
w.show()
sys.exit(app.exec_())
Still requires the upload of a 8kb .ui file and a 70kb sample database to run. So far I haven't been able to figure out how to do that....
When this is run, incorporating the rest of the necessary code, the author combobox works as expected, i.e.: the dropdown shows all the values in the author table and when I step the the records in the model, the correct author is displayed in the combobox.
The citation combobox does NOT function. As written here it neither shows values from the citation table, nor is it connected to the quotes table. Basically it shows nothing.
I think I need, somehow, a second delegate on the model. But I don't know how.
Any ideas how to get this functioning??
To make this work I had to change:
self.authorComboBox.setModel(self.model._authorModel)
to:
authorRel = self.model._formModel.relationModel(self.model.authorIdx)
self.authorComboBox.setModel(authorRel)
The QSqlRelationalTableModel has a virtual function "relationModel" that returns a QSqlTableModel. When you use this model as the model for the QComboBox, everything works.
I am pretty new to python and this is the first time I use tkinter so I hope someone can help me to find the right direction.
Basically this is what I would like to achieve:
I retrieve from an XML 2 lists (APPs, IDs);
The APP List will be shown in a Dropdown menu;
The APP selection in the Dropdown menu will call the APP status using its ID.
I can't get the last point work, basically I think I understand why (I have no matching between the two lists or a function to match them, and the selection calls automatically the last ID of second list) but I am to the best of my knowledge not able to solve it.
import requests
import xml.etree.ElementTree as ET
import tkinter as tk
APP_OPTIONS = []
ID_OPTIONS = []
session = requests.Session()
session.auth = ('USER', 'PW')
applications = session.get('https://getapplicationslist.myurl.com/application/')
applications_xml = applications.content
root = ET.fromstring(applications_xml)
for application in root.findall('application'):
app_name = application.find('name').text
app_id = application.find('id').text
APP_OPTIONS.append(app_name)
ID_OPTIONS.append(app_id)
def appcall(*args):
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + app_id)
status_xml = app_status.content
root = ET.fromstring(status_xml)
for appStatus in root.findall('appStatus'):
status = appStatus.find('status').text
print(status)
root = tk.Tk()
root.title('Application List')
root.geometry("300x200")
var =tk.StringVar(root)
var.set('Choose an Application')
var.trace('w', appcall)
dropDownMenu = tk.OptionMenu(root, var, *APP_OPTIONS)
dropDownMenu.pack()
root.mainloop()
print('End Request')
As mentioned in my comment, the issue is your app_id in appcall does not change. You need to get the corresponding ID from the ID_OPTIONS instead.
def appcall(*args):
app_id = ID_OPTIONS[APP_OPTIONS.index(var.get())] # Add this line
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + app_id)
...
The app_id is now set to the ID_OPTIONS of the same index based on the app_name (since the insertion order is the same).
However, a better approach would be to initialize your options as a dictionary instead:
# instead of APP_OPTIONS / ID_OPTIONS, create:
apps = {}
...
for application in root.findall('application'):
app_name = application.find('name').text
app_id = application.find('id').text
# add to dictionary here:
apps[app_name] = app_id
def appcall(*args):
# Change the app_id to apps.get(var.get())
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + apps.get(var.get())
...
See how much simpler it is to recall the same reference?
If you are feeling comfortable about the language, you might even opt for a dictionary comprehension:
...
root = ET.fromstring(applications_xml)
app_id = {application.find('name').text: application.find('id').text for application in root.findall('application')}
...
In this simple program I'm drawing a window, adding a search box, getting a search term for the user, looking that up in a postgreSQL DB and displaying the reults. It works up to a point - when the user enters a second query.
I have tried in two different ways but each way gives a different problem. In the first way (lines 32-35 http://pastebin.com/q5bnLxaB) I'm creating the output window in the main and passing that to the search function. It crashes with gtk_scrolled_window_add: assertion 'child_widget == NULL' failed. I think because I'm adding the tree to the window when it has already been done. To fix this, I would need to reset the window somehow.
In the second way (lines 56-58) I have added the output window only in the search function so it no longer has this crashing issue. However, the window itself does not update with the results of a second or subsequent search.
Which, if either, of these methods seems the most sensible? I also need to consider that the next step is adding a clickable button beside each search term which will display extended data for each returned result.
BTW, in both cases the output window does not appear until a search is entered. It doesn't hinder functionality but it strange to me.
#!/usr/bin/python
from gi.repository import Gtk
from gi.repository.GdkPixbuf import PixbufLoader
import urllib2
import psycopg2
import sys
class NotebookWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Rugby Database")
#Create Application Window
self.set_border_width(10)
self.set_default_size(800, 600)
self.set_position(Gtk.WindowPosition.CENTER)
#Add external container (box)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(vbox)
#Add tabbed window
nbook = Gtk.Notebook()
vbox.pack_start(nbook, True, True, 0)
nbook.show()
#Add Main tab
label = Gtk.Label()
label.set_markup("<b><big>Main</big></b>")
table = Gtk.Table(rows=40, columns=10)
#Add Results field
#results_box = Gtk.ScrolledWindow()
#results_box.set_vexpand(True)
#table.attach(results_box, 0, 1, 1, 39, xpadding=5, ypadding=5)
#Add Search box
entry = Gtk.Entry()
entry.set_property("secondary-icon-stock", Gtk.STOCK_FIND)
entry.connect("icon-press", self.on_search_button)
#entry.connect("activate", self.on_search_enter, results_box)
entry.connect("activate", self.on_search_enter, table)
table.attach(entry, 0, 1, 0, 1, xpadding=5)
nbook.append_page(table, label)
def on_search_button(self, entry, icon, event):
search = entry.get_text()
print("Search for " + search)
def on_search_enter(self, entry, table): #changed from results_box
store = Gtk.ListStore(str, str, str)
tree = Gtk.TreeView(store)
##
results_box = Gtk.ScrolledWindow()
results_box.set_vexpand(True)
table.attach(results_box, 0, 1, 1, 39, xpadding=5, ypadding=5)
##
search = entry.get_text()
search = search.replace("'","''") #deal with apostrophes
entry.set_text("")
print("Search for " + search)
result = self.lookup_player(search)
print result
if len(result) > 0:
for i in range(0, len(result)):
store.append([result[i][0],result[i][1],str(result[i][4])])
print result[i][0],result[i][1],result[i][2],result[i][3],result[i][4],result[i][5],result[i][6],result[i][7],result[i][8]
else:
print "No players found"
#Add column for last name
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Last Name")
column.pack_start(renderer, True)
column.add_attribute(renderer, "text", 0)
tree.append_column(column)
#Add column for first name
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("First Name")
column.pack_start(renderer, True)
column.add_attribute(renderer, "text", 1)
tree.append_column(column)
#Add column for icon
renderer = Gtk.CellRendererPixbuf()
column = Gtk.TreeViewColumn("Show")
column.pack_start(renderer, True)
column.add_attribute(renderer, "stock-id", 2)
tree.append_column(column)
results_box.add(tree)
table.show_all()
tree.show_all()
def on_click_edit(self, button):
print("Editing Player")
def lookup_player(self, pstring):
try:
con = psycopg2.connect(database='Rugby', user='postgres', password = '1234')
cur = con.cursor()
search = "select pl.lastname, pl.firstname, pl.height, pl.weight, to_char(pl.dob, 'DD/MM/YYYY'), cl.name, pl.injury_id, to_char(pl.suspendeduntil, 'DD/MM/YYYY'), pl.photo from player pl inner join club cl on cl.id = pl.currentclub_id where firstname ilike '%s' or lastname ilike '%s'" % (pstring, pstring)
cur.execute(search)
result = cur.fetchall()
return result
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
win = NotebookWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Note This is a follow-up question to
Python (GTK) : Can someone explain the difference between TreeStore, Listmodel and all the rest?
as the original query has been answered and the scope has thus changed (BTW massive thanks to everyone who helped with that!)
You should do everything you can in __init__(). This includes creating the store (as an instance variable so you can use it in the search handler), creating all widgets (ScrolledWindow and TreeView) and also adding the columns to the treeview.
In the search handler you should only call clear() on the ListStore (to remove any old results) and then append new results to the store.