Multiple windows in Tkinter? - user-interface

I am new to programming, and I am having trouble finding a tutorial that teaches how to create a GUI that uses multiple windows. For example, If a user clicks a "lookup" button, a window pops up with the search results. How do I accomplish this? Is this possible within Tkinter?
Any suggestions/ references to sources would be greatly appreciated.
Thanks.

To create your first window, you create an instance of the Tk class. All other windows are instances of Toplevel.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
b1 = tk.Button(self, text="Add another window", command = self.newWindow)
b1.pack(side="top", padx=40, pady=40)
self.count = 0
def newWindow(self):
self.count += 1
window = tk.Toplevel(self)
label = tk.Label(window, text="This is window #%s" % self.count)
label.pack(side="top", fill="both", expand=True, padx=40, pady=40);
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()

import tkinter as tk
from tkinter import *
class Example(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
# b1 = tk.Button(self, text="Add another window", command = self.newWindow)
self.count = 0
self.canvas1 = Canvas(self, width=500, height=500)
b1 = tk.Button(self.canvas1, text="Add another window", command = self.create_new_window)
# b1.pack(side="top", padx=40, pady=40)
self.canvas1.pack(side="top")
b1.pack(side="top", padx=250, pady=240)
def create_new_window(self):
self.window1 = tk.Toplevel(self)
self.window1.geometry("+160+300")
self.canvas1 = Canvas(self.window1, width=50, height=500)
# label = tk.Label(self.window1, text="This is window #%s" % self.count)
self.canvas1.pack(side="top", fill="both")
def create_new_window2(self):
self.window2 = tk.Toplevel(self)
self.canvas2 = Canvas(self.window2, width=500, height=500)
# label = tk.Label(self.window2, text="This is window #%s" % self.count)
self.canvas2.pack(side="top", fill="both", expand=True, padx=40, pady=40)
if __name__ == "__main__":
root = tk.Tk()
root.geometry("+300+300")
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()

Related

Drag and drop image in Wxpython

I have created 3 panels in wxpython. One at top. And other 2 panels at bottom in vertical fashion. Panel2 consists of ListControl as list1 and Panel3 consist of ListControl as list2.
I have used wx.ImageList in conjunction with wx.ListCtrl in panel2 and panel3.
I am trying to drag the image from Panel2 to Panel3.
Have used:
self.list1.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.list1.GetId())
I have used wx.FileDropTarget to define Drop target and wx.BitmapDataObject in the def OnDragInit function.
Piece of code is as follows:
class MyTarget(wx.FileDropTarget):
def __init__(self, object):
wx.FileDropTarget.__init__(self)
self.object = object
def OnDropFiles(self, x, y, filenames):
print(filenames)
return(True)
def OnDragInit(self, event):
text = self.list1.GetBitmap(event.GetIndex())
too = wx.BitmapDataObject(text)
src = wx.DropSource(self.list2)
src.SetData(too)
src.DoDragDrop(True)
Issue: The drop target is not accepting data.
I suspect that you are not setting SetDropTarget.
See here, FileDrTr = MyFileDropTarget(self) and Drop_Place.SetDropTarget(FileDrTr)
import wx
import wx.lib.newevent
drop_event, EVT_DROP_EVENT = wx.lib.newevent.NewEvent()
class MyFileDropTarget(wx.FileDropTarget):
def __init__(self, obj):
wx.FileDropTarget.__init__(self)
self.obj = obj
def OnDropFiles(self, x, y, filename):
#filename is a list of 1 or more files
#here we are restricting it 1 file by only taking the first item of the list
TempTxt = filename[0]
evt = drop_event(data=TempTxt)
wx.PostEvent(self.obj,evt)
return True
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title)
self.InitUI()
self.Center()
def InitUI(self):
panel = wx.Panel(self)
FileDrTr = MyFileDropTarget(self)
font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)
font.SetPointSize(9)
verBox = wx.BoxSizer(wx.VERTICAL)
horBoxOne = wx.BoxSizer(wx.HORIZONTAL)
TextLabel = wx.StaticText(panel, label = 'Drop file here')
TextLabel.SetFont(font)
horBoxOne.Add(TextLabel, flag=wx.RIGHT, border=10)
Drop_Place = wx.TextCtrl(panel)
Drop_Place.SetDropTarget(FileDrTr)
#Bind the drop event listener
self.Bind(EVT_DROP_EVENT, self.LabelTextUpdate)
horBoxOne.Add(Drop_Place, proportion=1)
verBox.Add(horBoxOne, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
verBox.Add((-1, 10))
horBoxTwo = wx.BoxSizer(wx.HORIZONTAL)
self.NewText = wx.StaticText(panel, label = 'Path will be')
horBoxTwo.Add(self.NewText, flag=wx.RIGHT, border=5)
verBox.Add(horBoxTwo, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
panel.SetSizer(verBox)
def LabelTextUpdate(self, event):
txt = event.data
self.NewText.SetLabel(txt)
def main():
app = wx.App()
ex = Example(None, title = 'drop and see file path')
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
Note the target is the textctrl, dropping a file on the panel will achieve nothing, whilst dropping on the target (the textctrl called Drop_Place) will activate the event.

Tkinter not updating in Windows OS when scrolling too fast

As seen in the example above, a mixture of the Label objects on the left column or Entry objects on the right column are not shown when scrolling too fast.
If I click on the scrollbar and drag quickly it can look as bad as this. If I use the wheel on the mouse to scroll slowly it is typically fine, though sometimes a line will get missed no matter how slowly I scroll. For reference, it seems to always be the same line(s) that do not show when scrolling slowly.
Changing tabs back and forth causes everything to draw properly again. On Linux, everything works perfectly. But this needs to work on Windows as well.
Not sure if it matters, but each line is a Label and Entry inside of a Frame inside of a Canvas that, along with a Scrollbar, is inside of a Frame. Each of those top Frames is a "page" in a Notebook to provide the tabs shown on top.
And finally some questions. Is there a button I can add to force this to redraw without destroying and recreating it? Or possibly something I can add when creating these objects to force them to redraw when moved?
Sample code upon request:
#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText
class WriteableEntry(Label):
def __init__(self, name, value, *args, **kwargs):
#~ self.ip = ip
#~ self.ping_results = []
super(WriteableEntry, self).__init__(*args, **kwargs)
self.label = name
self.init_value = value
self.written_value = ''
self.field_name = Label(self, justify="left", text=name, width=25)
self.field_value = Entry(self, justify='left', width=60)
self.field_value.insert(END, value)
self.field_name.pack(side=LEFT)
self.field_value.pack(side=LEFT)
class InfoFrame(Frame):
def __init__(self, *args, **kwargs):
super(InfoFrame, self).__init__(*args, **kwargs)
self.nb_frame = Frame(self, height=300, width=730)
self.nb_frame.pack_propagate(False)
self.nb = ttk.Notebook(self.nb_frame)
self.nb.pressed_index = None
filler = {}
for x in range(0, 3):
for y in ('a', 'b', 'c', 'd', 'e', 'f', 'g'):
filler.update({"out%d_%s" % (x, y):"nada"})
self.example_dict = {'A':filler, 'B':filler, 'C':filler}
print("E_D:\n", self.example_dict)
for page in sorted(self.example_dict):
print("page:\t", page)
entry_count = len(self.example_dict[page])
# # ## Make new_page to put in nb
new_page = Frame(self.nb)
new_page.pack(fill=BOTH, expand=True)
# # ## Make canvas to put in that new_page
canvas = Canvas(new_page)
scroll = Scrollbar(new_page, command=canvas.yview)
## Orig *27
canvas.config(yscrollcommand=scroll.set, scrollregion=(0,120,120,entry_count * 35))
canvas.pack(side=LEFT, fill=BOTH, expand=True)
scroll.pack(side=RIGHT, fill=Y)
# # ## Make a frame to put in that canvas
canvas_frame = Frame(canvas, bg='white', width=50, height=50)
## Orig +12 *10
canvas.create_window(345, (entry_count + 12) * 13, window=canvas_frame)
for value in sorted(self.example_dict[page]):
print("value:\t", value)
writeable_entry = WriteableEntry(value, self.example_dict[page][value], master=canvas_frame)
writeable_entry.pack(side=TOP)
self.nb.add(new_page, text=page)
self.nb.pack(side=TOP, expand=True, fill="both")
self.nb_frame.pack(side=RIGHT, expand=True, fill=BOTH)
class IPLabel(LabelFrame):
def __init__(self, *args, **kwargs):
super(IPLabel, self).__init__(*args, **kwargs)
self.info_frame = InfoFrame(master=self)
self.info_frame.grid(row=1, columnspan=2, sticky=E + W)
class AvailableApplication(Frame):
def __init__(self, master):
super(AvailableApplication, self).__init__(master)
#~ self.ips = ips
self.grid()
self.grid_propagate(True)
self.ip_widgets = []
self.createWidgets()
def createWidgets(self):
self.ip_frame = Frame(self)
self.ip_widgets = []
ip_widget = IPLabel(master=self.ip_frame)
ip_widget.grid(row=0, column=1, columnspan=4, sticky=E + W)
self.ip_widgets.append(ip_widget)
self.ip_frame.grid(row=1, column=0, columnspan=8)
self.ip_frame.grid_propagate(True)
if __name__ == "__main__":
root = Tk()
root.title("Example Script")
app = AvailableApplication(root)
app.mainloop()
root.destroy()
The main problem is the WriteableEntry. It is not a tk.Label. You can't have sub widgets (a tk.Label and a tk.Entry) of a tk.Label. You also have the wrong layout manager for this work. Maybe also because of the wrong sub widget use. You rely on the wrap behavior of the pack manager. Don't. Use the grid() manager.
For some reason tab C is not visible but that is another problem.
Using Ctrl-Tab I found that there is a third tab but the tab text was the empty string. Adding the tab with
self.nb.add(new_page, text="P"+page)
Made it better visible. I have no idea why the tab name "C" has a special meaning for tkinter
The only possible way to kill the App and window is by using the Close button. So why do you destroy the root window? It is already destroyed.
#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText
class WriteableEntry(object):
def __init__(self, name, value, *args, **kwargs):
#~ self.ip = ip
#~ self.ping_results = []
#super(WriteableEntry, self).__init__(*args, **kwargs)
master = kwargs['master']
row = kwargs['row']
self.label = name
self.init_value = value
self.written_value = ''
self.field_name = Label(master, justify="left", text=name, width=25)
self.field_value = Entry(master, justify='left', width=60)
self.field_value.insert(END, value)
self.field_name.grid(row=row, column=0)
self.field_value.grid(row=row, column=1)
class InfoFrame(Frame):
def __init__(self, *args, **kwargs):
super(InfoFrame, self).__init__(*args, **kwargs)
self.nb_frame = Frame(self, height=300, width=730)
self.nb_frame.pack_propagate(False)
self.nb = ttk.Notebook(self.nb_frame)
self.nb.pressed_index = None
filler = {}
for x in range(0, 3):
for y in ('a', 'b', 'c', 'd', 'e', 'f', 'g'):
filler.update({"out%d_%s" % (x, y):"nada"})
self.example_dict = {'A':filler, 'B':filler, 'C':filler}
print("E_D:\n", self.example_dict)
for page in sorted(self.example_dict):
print("page:\t", page)
entry_count = len(self.example_dict[page])
# # ## Make new_page to put in nb
new_page = Frame(self.nb)
new_page.pack(fill=BOTH, expand=True)
# # ## Make canvas to put in that new_page
canvas = Canvas(new_page)
scroll = Scrollbar(new_page, command=canvas.yview)
## Orig *27
canvas.config(yscrollcommand=scroll.set, scrollregion=(0,120,120,entry_count * 35))
canvas.pack(side=LEFT, fill=BOTH, expand=True)
scroll.pack(side=RIGHT, fill=Y)
# # ## Make a frame to put in that canvas
canvas_frame = Frame(canvas, bg='white', width=50, height=50)
## Orig +12 *10
canvas.create_window(345, (entry_count + 12) * 13, window=canvas_frame)
for row, value in enumerate(sorted(self.example_dict[page])):
print("value:\t", value)
writeable_entry = WriteableEntry(value, self.example_dict[page][value], master=canvas_frame, row=row)
#writeable_entry.pack(side=TOP)
self.nb.add(new_page, text="P"+page)
self.nb.pack(side=TOP, expand=True, fill="both")
self.nb_frame.pack(side=RIGHT, expand=True, fill=BOTH)
class IPLabel(LabelFrame):
def __init__(self, *args, **kwargs):
super(IPLabel, self).__init__(*args, **kwargs)
self.info_frame = InfoFrame(master=self)
self.info_frame.grid(row=1, columnspan=2, sticky=E + W)
class AvailableApplication(Frame):
def __init__(self, master):
super(AvailableApplication, self).__init__(master)
#~ self.ips = ips
self.grid()
self.grid_propagate(True)
self.ip_widgets = []
self.createWidgets()
def createWidgets(self):
self.ip_frame = Frame(self)
self.ip_widgets = []
ip_widget = IPLabel(master=self.ip_frame)
ip_widget.grid(row=0, column=1, columnspan=4, sticky=E + W)
self.ip_widgets.append(ip_widget)
self.ip_frame.grid(row=1, column=0, columnspan=8)
self.ip_frame.grid_propagate(True)
if __name__ == "__main__":
root = Tk()
root.title("Example Script")
app = AvailableApplication(root)
app.mainloop()
#root.destroy()

PyQt how to capture print output and display in text field

The following script is part of a more complex one. I have taken out some parts just for simplification.
My aim is to insert a textedit field that captures the print output of the command window (when the pushbutton is pressed) and displays it inside the text field while the program is executing.
The suggestions I found are too much aimed at scripts that have no other functions. But my script is already quite complex and I don’t want to change it from the beginning or rewrite the whole script.
Does anyone have an idea on how to include the function in the script in a relatively simple way? I have tried it without success.
Any kind help would be appreciated.
import sys
import subprocess
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.win_widget = WinWidget(self)
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout(widget)
layout.addWidget(self.win_widget)
self.setCentralWidget(widget)
self.statusBar().showMessage('Ready')
self.setGeometry(300, 300, 450, 250)
self.setWindowTitle('capture PyQt output')
self.setWindowIcon (QtGui.QIcon('logo.png'))
self.show()
class WinWidget (QtGui.QWidget) :
def __init__(self, parent):
super (WinWidget , self).__init__(parent)
self.controls()
self.grid_layout()
self.capture_output()
def controls(self):
self.btn_newSearch = QtGui.QPushButton('capture PyQt output', self)
self.btn_newSearch.clicked.connect(self.some_funtion)
self.btn_newSearch.setFont(QtGui.QFont('CourierNew', 12 , QtGui.QFont.Bold,False))
def capture_output (self) :
# HERE I WANT TO PUT A (IF POSSIBLE SIMPLE) SCRIPT TO CAPTURE
COOMAND WINDOW OUTPUT
something like:
self.text_box = QtGui.QPlainTextEdit()
text= capured output
self.text_box.setPlainText(text)
def grid_layout (self) :
grid = QtGui.QGridLayout()
grid.setSpacing(2)
grid.addWidget(self.btn_newSearch , 1 , 1)
grid.addWidget(self.text_box , 2 , 1)
self.setLayout(grid)
def some_funtion (self) :
print "hello world"
def main():
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Can I make a QToolButton perform QLabel.setLayout(someLayout)? -- setting row height isn't working

My only GUI experience is with java.swing. I'm using PySide to update which of two QGridLayouts are set to a QLabel depending on a button press, but the actual update isn't happening. Making a call to self.update() after lines 123 and 130 didn't work. Should I be using a repaint event or something?
def displaySimulator(self):
if self.sim_vis == True: pass
else:
self.sim_vis = True
self.graph_vis = False
self.options.setLayout(self.simulator_settings)
def displayGraphing(self):
if self.graph_vis == True: pass
else:
self.graph_vis = True
self.sim_vis = False
self.options.setLayout(self.graphing_settings)
Here's the full code.
----------------------------------------------------------------------------------
Also, the toolbar label at the top is way too big...
self.layout.setRowMinimumHeight(0,20)
self.layout.setColumnMinimumWidth(0,250)
self.layout.setColumnMinimumWidth(1,1000)
setColumnMinimumWidth() works fine but setRowMinimumHeight() doesn't seem to work at all. I'm still a little confused about how the size of QWidgets are affected by layouts, containers, and subwidgets...perhaps I need to adjust the size of the QLabel, toolbar?
Try using a QWidget instead of a QLabel for self.options. Does that change anything?
For the toolbar spacing, do addStretch() after you add the last widget to the layout, but note that if you use a layout in a toolbar, you lose the built-in capabilities for it to autosize and hide buttons in a "... more options ..." type thing.
Since you name your object a toolbar I would actually make it a QToolbar. I would like to point out some styling points, because you said you were new.
import * is always bad for many reasons. You should know what you are importing and from where.
from PySide import QtGui, QtCore
Since you have a main GUI that you are running I would make that a QMainWindow. I would then add a menu bar and move some of your functionality to a file menu or edit menu.
This is just my style and how I like to do things
import sys
from PySide import QtGui, QtCore
class SimulatorWindow(QtGui.QMainWindow):
"""Application for running a simulator and displaying the resutls."""
def __init__(self):
super(SimulatorWindow, self).__init__()
self.setWindowTitle("Simulator") # Main window
# Properties
self.main_menu = None
self.simulator = None
self.export_action = None
self.settings_action = None
self.exit_action = None
self.initUI()
self.initMenu()
self.resize(600, 400)
# end Constructor
# Builds Simulator GUI
def initUI(self):
self.simulator = Simulator()
self.setCentralWidget(self.simulator)
self.addToolBar(self.simulator.toolbar)
# end initUI
def initMenu(self):
"""Initialize the menu bar."""
menubar = self.menuBar()
# ===== File Menu =====
self.file_menu = menubar.addMenu('&File')
# Export action
iexport = QtGui.QIcon()
self.export_action = QtGui.QAction(iexport, "Export", self)
self.export_action.triggered.connect(self.export)
self.file_menu.addAction(self.export_action)
# Separator
self.file_menu.addSeparator()
# Simulator Settings Dialog action
isettings = QtGui.QIcon()
self.settings_action = QtGui.QAction(isettings, "Settings", self)
self.settings_action.triggered.connect(self.simulator.dialog.show)
self.file_menu.addAction(self.settings_action)
# Exit action
iexit = QtGui.QIcon('exit.png')
self.exit_action = QtGui.QAction(iexit, '&Exit', self)
self.exit_action.triggered.connect(self.close)
self.file_menu.addAction(self.exit_action)
# ===== Edit Menu =====
self.edit_menu = menubar.addMenu('&Edit')
self.edit_menu.addAction(self.simulator.run_action)
# end initMenu
def export(self):
"""Export the simulation file."""
pass
# end export
# end class SimulatorWindow
class Simulator(QtGui.QWidget):
"""Simulator display."""
def __init__(self):
super().__init__()
#Properties
self.toolbar = None
self.dialog = None
self.run_action = None
# Layout
self.main_layout = QtGui.QGridLayout()
self.setLayout(self.main_layout)
# Graph
stuff = QtGui.QLabel("<font color=red size=300>Graphing stuff</font>")
stuff.setStyleSheet("QLabel {background-color: rgb(50,50,50); font-size:250;}")
stuff.setAlignment(QtCore.Qt.AlignCenter)
graph = QtGui.QLabel("<font color=green size=250>Graph here</font>")
graph.setStyleSheet("QLabel {background-color: rgb(0,0,0); font-size:250;}")
graph.setAlignment(QtCore.Qt.AlignCenter)
graph.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
self.main_layout.addWidget(stuff)
self.main_layout.addWidget(graph)
self.initToolbar()
self.initSettingsDialog()
# end Constructor
def initToolbar(self):
self.toolbar = QtGui.QToolBar()
irun = QtGui.QIcon()
self.run_action = QtGui.QAction(irun, "Run", self)
self.run_action.triggered.connect(self.run)
self.toolbar.addAction(self.run_action)
# end initToolbar
def initSettingsDialog(self):
"""Initialize the Settings dialog."""
self.dialog = QtGui.QDialog(self)
self.dialog.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.WindowSystemMenuHint)
layout = QtGui.QGridLayout()
self.dialog.setLayout(layout)
# Initialize the Widgets
title = QtGui.QLabel("<font size=6>Simulator Settings</font>")
num_sim = QtGui.QLineEdit("Number of simulations")
num_trials = QtGui.QLineEdit("Number of trials (per learning phase)")
network = QtGui.QComboBox()
subject = QtGui.QComboBox()
# Set the layout
layout.addWidget(title, 0, 0, 1, 2, QtCore.Qt.AlignCenter)
layout.addWidget(num_sim, 1, 0)
layout.addWidget(num_trials, 1, 1)
layout.addWidget(network, 2, 0)
layout.addWidget(subject, 2, 1)
# end initSettingsDialog
def run(self):
"""Run the simulation."""
pass
# end run
# end class Simulator
def main():
"""Run the application."""
app = QtGui.QApplication(sys.argv)
window = SimulatorWindow()
window.show()
return app.exec_()
# end main
if __name__ == "__main__":
sys.exit(main())

PySide crash on exit (using QCompleter)

I have reproduced the "Custom Completer Example" from the Qt documentation using PySide
(Python 2.7.3, PySide 1.1.2, Qt 4.8.1).
I have an issue where a win32 exception is thrown on exit (or on Mac OS X a access violation exception).
On the Mac I can see a stack trace and the issue occurs during garbage collection, where references to QObjects are apparently not consistent, such that things go bad.
I can see this crash with the following self-contained script, only if a completer insertion was accepted. I.e. type the first few letters, then accept the completion.
On the other hand, if I have seen the completion list popup, but not accepted the completion, no crash occurs on exit.
################################################################################
# Completer.py
#
# A PySide port of the Qt 4.8 "Custom Completer Example"
# http://qt-project.org/doc/qt-4.8/tools-customcompleter.html
#
################################################################################
from PySide.QtCore import *
from PySide.QtGui import *
class TextEdit(QPlainTextEdit):
def __init__(self, parent=None):
super(TextEdit, self).__init__(parent)
self.c = None
def completer(self):
return self.c
def setCompleter(self, completer):
if self.c:
QObject.disconnect(self.c, 0, self, 0)
self.c = completer
if not self.c:
return
self.c.setWidget(self)
self.c.setCompletionMode(QCompleter.PopupCompletion)
self.c.setCaseSensitivity(Qt.CaseInsensitive)
self.c.activated.connect(self.insertCompletion)
def insertCompletion(self, completion):
if self.c.widget() is not self:
return
tc = self.textCursor()
extra = len(completion) - len(self.c.completionPrefix())
tc.movePosition(QTextCursor.Left)
tc.movePosition(QTextCursor.EndOfWord)
tc.insertText(completion[-extra:])
self.setTextCursor(tc)
def textUnderCursor(self):
tc = self.textCursor()
tc.select(QTextCursor.WordUnderCursor)
return tc.selectedText()
def focusInEvent(self, event):
if self.c:
self.c.setWidget(self)
super(TextEdit, self).focusInEvent(event)
def keyPressEvent(self, e):
if self.c and self.c.popup().isVisible():
if e.key() in (Qt.Key_Enter,
Qt.Key_Return,
Qt.Key_Escape,
Qt.Key_Tab,
Qt.Key_Backtab):
e.ignore()
return
# Check for the shortcut combination Ctrl+E
isShortcut = (e.modifiers() & Qt.ControlModifier) and e.key() == Qt.Key_E
# Do not process the shortcut when we have a completion
if not self.c or not isShortcut:
super(TextEdit, self).keyPressEvent(e)
noText = not e.text()
ctrlOrShift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
if not self.c or (ctrlOrShift and noText):
return
eow = "~!##$%^&*()_+{}|:\"<>?,./;'[]\\-=" # End of word
hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
completionPrefix = self.textUnderCursor()
if not isShortcut and \
(hasModifier or noText or len(completionPrefix) < 1 or e.text()[-1:] in eow):
self.c.popup().hide()
return
if completionPrefix != self.c.completionPrefix():
self.c.setCompletionPrefix(completionPrefix)
self.c.popup().setCurrentIndex( self.c.completionModel().index(0,0) )
cr = self.cursorRect()
cr.setWidth(self.c.popup().sizeHintForColumn(0) + \
self.c.popup().verticalScrollBar().sizeHint().width())
self.c.complete(cr)
class Completer(QMainWindow):
words = ("one",
"two",
"three",
"four")
def __init__(self, parent=None):
super(Completer, self).__init__(parent)
self.setWindowTitle("Completer")
self.textEdit = TextEdit()
self.completer = QCompleter(self)
self.completer.setModelSorting(QCompleter.CaseInsensitivelySortedModel)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.completer.setWrapAround(False)
self.completer.setModel(QStringListModel(Completer.words, self.completer))
self.textEdit.setCompleter(self.completer)
self.setCentralWidget(self.textEdit)
self.resize(500, 300)
self.setWindowTitle("Completer")
if __name__ == '__main__':
import sys
from PySide.QtGui import QApplication
app = QApplication(sys.argv)
window = Completer()
window.show()
sys.exit(app.exec_())

Resources