qtablewidget example for entering data into the table - qtablewidget

I need to create a tablewidget with 3 columns and multiple rows…
I was able to create the columns and headers but Iam unable to enter data into the table…
So please help me as soon as possible…
Thankyou

I hope this helps (20 rows, 3 columns, with text - cellID, in every cell).
If you need something else, feel free to ask...
from PyQt4 import QtGui
class Table(QtGui.QDialog):
def __init__(self, parent=None):
super(Table, self).__init__(parent)
layout = QtGui.QGridLayout()
self.table = QtGui.QTableWidget()
self.table.setRowCount(20)
self.table.setColumnCount(3)
layout.addWidget(self.table)
self.enterDataInTable()
self.setLayout(layout)
def enterDataInTable(self):
for i in range(0,20):
for j in range(0,3):
self.table.setItem(i, j, QtGui.QTableWidgetItem("cell %s-%s"%(i+1,j+1)))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
t = Table()
t.show()
sys.exit(app.exec_())

Related

Retrieve data when clicking a button

Trying to receive input from WCT_Control into WCT_DataPull
Cant figure out how to get the data into WCT_DataPull to perform an action with it. I think I am going about this backwards, but I also think I have been staring at it too long.
Essentially, the user enters the information necessary into a GUI to connect to a specific SQL table (predetermined) and then saves the data in the table and outputs it as a csv file backup.
I want the user to click the submit button and that creates the backup. However, at this point when I click the button, it will store all the data in the variables (If I put a print statement in I see the correct values), but I cant seem to figure out how to get the variables to WCT_DataPull, where the backup creation action is performed.
WCT_Control
from PyQt5.QtWidgets import *
from WCT_View import Ui_MainWindow
class Controller(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
self.run.clicked.connect(lambda : self.submit())
def submit(self):
self.run.clicked.connect()
server = self.server_entry.text()
database = self.data_entry.text()
station = self.station_entry.text()
app = self.app_entry.text()
backup_name = self.filename_entry.text()
self.server_entry.setText('')
self.data_entry.setText('')
self.station_entry.setText('')
self.app_entry.setText('')
self.filename_entry.setText('')
return server, database, station, app, backup_name
WCT_DataPull
from WCT_Control import *
import pyodbc
import csv
pull_data = Controller()
def write_bak():
driver = 'ODBC Driver 17 for SQL Server'
serv, data, stat, app, bak_name = pull_data.submit()
conn = pyodbc.connect('DRIVER={0};SERVER={1};DATABASE={2};Trusted_Connection=yes'.format(driver, serv, data))
cursor = conn.cursor()
rows = cursor.execute("""
select DnsName, PackageName, Code, Value from WorkstationApplicationSettings
where DnsName=? and PackageName=?
""", stat, app).fetchall()
for row in rows:
print(row.PackageName,':', row.Code, ':', row.Value)
with open(bak_name, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerows(rows)
So you just have to do the things in opposite way, instead of using PYQT5 in WCT script, use the WCT function in PYQT5 script
WCT_Control
from PyQt5.QtWidgets import *
from WCT_DataPull import write_bak
class Controller(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
self.run.clicked.connect(lambda : self.submit())
def submit(self):
self.run.clicked.connect()
server = self.server_entry.text()
database = self.data_entry.text()
station = self.station_entry.text()
app = self.app_entry.text()
backup_name = self.filename_entry.text()
self.server_entry.setText('')
self.data_entry.setText('')
self.station_entry.setText('')
self.app_entry.setText('')
self.filename_entry.setText('')
write_bak(serv, data, stat, app, bak_name)
WCT_DataPull
import pyodbc
import csv
def write_bak(serv, data, stat, app, bak_name):
driver = 'ODBC Driver 17 for SQL Server'
conn = pyodbc.connect('DRIVER={0};SERVER={1};DATABASE={2};Trusted_Connection=yes'.format(driver, serv, data))
cursor = conn.cursor()
rows = cursor.execute("""
select DnsName, PackageName, Code, Value from WorkstationApplicationSettings
where DnsName=? and PackageName=?
""", stat, app).fetchall()
for row in rows:
print(row.PackageName,':', row.Code, ':', row.Value)
with open(bak_name, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerows(rows)
Also Make sure to write the code to run the WCT_control by using Qapplication

TabularAdapter customization/notifications?

Thanks to another user here on SO (Warren Weckesser), I found a nice way to format my TabularAdapter columns. There are some other customizations I'd like to accomplish, so I thought I'd put this out to SO to see if I can get more help.
The following code puts up a couple of TabularAdapter tables in the format that I want to use. What I'd like to be able to do are 2 things:
I'd like to set the first column as non-editable. I've found how to set a row to non-editable, but not a column -- is this possible?
What I'd really like (even more than #1 above) it to get a notification if one of the values in any of my columns changes! I've heard that there are some 'tweaks' that can be done with numpy arrays to accomplish this, but I'm way too inexperienced yet to pull this off. Is there any TraitsAdapter mentods that might be used to accomplish this feat?
Here's my code so far (thanks to Warren's modifications):
from traits.api import HasTraits, Array, Str
from traitsui.api import View, Item, TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import dtype
test_dtype = dtype([('Integer#1', 'int'),
('Integer#2', 'int'),
('Float', 'float')])
class TestArrayAdapter1(TabularAdapter):
columns = [('Col1 #', 0), ('Col2', 1), ('Col3', 2)]
even_bg_color = 0xf4f4f4 # very light gray
width = 125
def get_format(self, object, name, row, column):
formats = ['%d', '%d', '%.4f']
return formats[column]
class TestArrayAdapter2(TabularAdapter):
columns = [('Col1 #', 0), ('Col2', 1), ('Col3', 2)]
even_bg_color = 0xf4f4f4 # very light gray
width = 125
object_0_format = Str("%d")
object_1_format = Str("%d")
object_2_format = Str("%.4f")
class Test(HasTraits):
test_array = Array(dtype=test_dtype)
view = \
View(
Item(name='test_array', show_label=False,
editor=TabularEditor(adapter=TestArrayAdapter1())),
Item(name='test_array', show_label=False,
editor=TabularEditor(adapter=TestArrayAdapter2())),
)
test = Test()
test.test_array.resize(5, refcheck=False)
test.configure_traits()
For your item #2, after talking to Enthought folks, I confirmed there isn't an official way to do this yet but:
I created a ticket for it: https://github.com/enthought/traitsui/issues/387
I worked around the issue, by keeping a handle on the ArrayAdapter, subclass it, and override the set_text method like so:
.
class NotifyingArrayAdapter(ArrayAdapter):
value_changed = Event
def set_text(self, object, trait, row, column, text):
super(NotifyingArrayAdapter, self).set_text(object, trait, row,
column, text)
self.value_changed = True
That way, I can just listen to the value_changed event, and do what I need with it.
You can get fancier, and make the event be a more complex object, for example storing information about the old/new values, and the row and column changed:
class ArrayAdapterEvent(HasStrictTraits):
row = Int
column = Int
old = Str
new = Str
class NotifyingArrayAdapter(ArrayAdapter):
value_changed = Event(Instance(ArrayAdapterEvent))
def set_text(self, object, trait, row, column, text):
old = self.get_text(object, trait, row, column)
super(NotifyingArrayAdapter, self).set_text(object, trait, row,
column, text)
event = ArrayAdapterEvent(old=old, new=text, row=row, column=column)
self.value_changed = event

PyQt4 QComboBox autocomplete without using setModel?

I have found several excellent examples of a PyQt4 QComboBox with autocomplete (e.g. How do I Filter the PyQt QCombobox Items based on the text input?), but they all use setModel and setSourceModel... etc.
Is it possible to create an autocomplete QComboBox in PyQt4 without using a model?
Using smitkpatel's comment... I found a setCompleter example which works. It was posted by flutefreak at QComboBox with autocompletion works in PyQt4 but not in PySide.
from PyQt4 import QtCore
from PyQt4 import QtGui
class AdvComboBox(QtGui.QComboBox):
def __init__(self, parent=None):
super(AdvComboBox, self).__init__(parent)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.setEditable(True)
# add a filter model to filter matching items
self.pFilterModel = QtGui.QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# add a completer, which uses the filter model
self.completer = QtGui.QCompleter(self.pFilterModel, self)
# always show all (filtered) completions
self.completer.setCompletionMode(QtGui.QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)
# connect signals
def filter(text):
print "Edited: ", text, "type: ", type(text)
self.pFilterModel.setFilterFixedString(str(text))
self.lineEdit().textEdited[unicode].connect(filter)
self.completer.activated.connect(self.on_completer_activated)
# on selection of an item from the completer, select the corresponding item from combobox
def on_completer_activated(self, text):
if text:
index = self.findText(str(text))
self.setCurrentIndex(index)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
combo = AdvComboBox()
names = ['bob', 'fred', 'bobby', 'frederick', 'charles', 'charlie', 'rob']
combo.addItems(names)
combo.resize(300, 40)
combo.show()
sys.exit(app.exec_())

How can I use pyglet batches to draw scenes or levels

So I'm currently learning pyglet for Python 2.7 and I'm trying to make a simple game that has levels. The 1st 'scene' would be the title/intro part, 2nd would be a tutorial of some sort, and the rest are the game levels themselves.
For this, I've created 7 batches(1 intro, 1 tutorial, 5 levels) namely batch, batch1, ... batch6. I've also created 7 classes for each of these batches that represent the scenes/levels. This is what I've done for the intro batch and class:
batch = pyglet.graphics.Batch()
batch1 = pyglet.graphics.Batch()
class StartState:
def __init__(self):
self.welcome = pyglet.text.Label('WELCOME TO', font_name='Arial', font_size=32, color=(200,255,255,255), x=400, y=550, anchor_x='center', anchor_y='center', batch=batch)
self.title = pyglet.text.Label("MY GAME", font_name='Arial', font_size=32, color=(100,200,170,255), x=400, y=450, anchor_x='center', anchor_y='center', batch=batch)
self.press = pyglet.text.Label("press 'SPACE' to continue", font_name='Arial', font_size=32, color=(200,255,150,255), x=400, y=250, anchor_x='center', anchor_y='center', batch=batch)
def update(self, dt):
if keymap[pyglet.window.key.SPACE]:
self.welcome.delete()
self.title.delete()
self.press.delete()
states.pop()
batch1.draw()
The other scenes would also look like that. the states list is a list that I use to store my classes/scenes. states = [Level5(), Level4(), ... , TutorialState(), StartState()]. So every time the condition to advance is fulfilled, which in this class is to press 'SPACE', the window will be 'cleared' i.e. delete the sprites/labels and proceed to the next scene by using states.pop() and batch1.draw().
After I've typed these classes, I added this at the end:
#window.event
def on_draw():
window.clear()
batch.draw()
def update(dt):
if len(states):
states[-1].update(dt)
else:
pyglet.app.exit()
states.append(Level5())
states.append(Level4())
states.append(Level3())
states.append(Level2())
states.append(Level1())
states.append(TutorialState())
states.append(StartState())
pyglet.clock.schedule_interval(update, 1.0/60.0)
window.clear()
window.flip()
window.set_visible(True)
pyglet.app.run()
The problem here is that it only loads the starting batch/scene. Whenever I press 'SPACE' to go to the tutorial scene the labels/sprites of the starting batch disappear but it doesn't draw batch1 or load the the tutorial class/scene. Any suggestions?
After creating a batch for each scene class:
import pyglet
from pyglet.window import key
class SceneTemplate(object):
"""a template with common things used by every scene"""
def __init__(self, text):
self.batch = pyglet.graphics.Batch()
self.label = pyglet.text.Label(
text,
font_name='Arial', font_size=32,
color=(200, 255, 255, 255), x=32, y=704,
batch=self.batch)
# (...)
class MainMenuScene(SceneTemplate):
def __init__(self):
super(MainMenuScene, self).__init__(text='MainMenuScene')
# (...)
class IntroScene(SceneTemplate):
def __init__(self):
super(IntroScene, self).__init__(text='Introduction')
# (...)
class Level1(SceneTemplate):
def __init__(self):
super(Level1, self).__init__(text='Level 1')
# (...)
You can control the state/scene in another class, such as a window class (personally I like to subclass the pyglet window, to keep things organized and some other reasons):
class Window(pyglet.window.Window):
def __init__(self):
super(Window, self).__init__(width=1024, height=768)
self.states = [MainMenuScene(), IntroScene(), Level1()] # and so on...
self.current_state = 0 # later you change it to get the scene you want
self.set_visible()
def on_draw(self):
self.clear()
self.states[self.current_state].batch.draw()
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
new_state = self.current_state + 1
new_state = new_state % len(self.states)
self.current_state = new_state
# if you want each scene to handle input, you could use pyglet's push_handlers(), or even something like:
# self.states[self.current_state].on_key_press(symbol, modifiers)
# giving them access to the window instance might be needed.
if __name__ == '__main__':
window = Window()
pyglet.app.run()

PySide - QSortFilterProxyModel and QListView - indexWidget pointer get deleted when filtering

I've a problem with a custom QListView I'm trying to make, here the problem:
I'm using QListView to show a list of QWidget by using QListView.setIndexWidget(index,widget).
This is working pretty fine, but now I want to filter the items model by using QSortFilterProxyModel()
with .setFilterWildcard()
It is not working very well because the second time the model is filtered
I got error like this :
RuntimeError: Internal C++ object (PySide.QtGui.QLabel) already deleted.
Without using filtering and QSortFilterProxyModel everything works fine, but it seems I'm missing
something with the filtering operation, the indexWidget() is deleted when using filtering :(
here a sample code where you can reproduce the bug, when list view is shown, hit 1,2 or 3 keyboard
key to activate filtering ( Backspace to set filtering empty to show all items )
Here the sample code to reproduce the problem:
import PySide.QtGui as QtGui
import PySide.QtCore as QtCore
_DEFAULT_ITEM_SIZE = QtCore.QSize(100, 85)
_USER_ROLE = QtGui.QStandardItem.UserType + 1
class CustomItemWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CustomItemWidget, self).__init__(parent=parent)
#self.setAutoFillBackground(True)
self.main_layout = QtGui.QVBoxLayout(self)
self.label = QtGui.QLabel(self)
self.main_layout.addWidget(self.label)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
# Default brush and pen
bg_brush = QtGui.QBrush(QtGui.QColor("#8C8C8C"))
pen = QtCore.Qt.NoPen
painter.save()
painter.setPen(pen)
painter.setBrush(bg_brush)
painter.drawRoundedRect(self.rect(), 12, 12)
painter.restore()
def setData(self, role, value):
if role == QtCore.Qt.DisplayRole:
self.label.setText(value)
class CustomItem(QtGui.QStandardItem):
def __init__(self):
super(CustomItem, self).__init__()
self.number = None
self.item_widget = CustomItemWidget()
self.setSelectable(True)
def type(self):
return _USER_ROLE
def data(self, role):
if role == QtCore.Qt.DisplayRole:
value = "DATA %s" % str(self.number)
self.item_widget.setData(role, value)
return value
if role == QtCore.Qt.SizeHintRole:
return _DEFAULT_ITEM_SIZE
return QtGui.QStandardItem.data(self, role)
class CustomItemDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent=None):
super(CustomItemDelegate, self).__init__(parent=parent)
class CustomItemModel(QtGui.QStandardItemModel):
def __init__(self, parent=None):
super(CustomItemModel, self).__init__(parent)
def flags(self, index):
return QtCore.Qt.ItemIsEnabled | \
QtCore.Qt.ItemIsSelectable | \
QtCore.Qt.ItemIsDragEnabled | \
QtCore.Qt.ItemIsDropEnabled
class CustomItemFilterProxyModel(QtGui.QSortFilterProxyModel):
def __init__(self, parent=None):
super(CustomItemFilterProxyModel, self).__init__(parent)
self.setDynamicSortFilter(True)
self.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.setFilterKeyColumn(0)
class CustomView(QtGui.QListView):
def __init__(self, parent=None):
super(CustomView, self).__init__(parent=parent)
self.setIconSize(_DEFAULT_ITEM_SIZE)
self.setMovement(QtGui.QListView.Static)
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)
self.setViewMode(QtGui.QListView.IconMode)
self.setUniformItemSizes(True)
self.setFlow(QtGui.QListView.LeftToRight)
self.setResizeMode(QtGui.QListView.Adjust)
self.data_model = CustomItemModel(self)
self.proxy_model = CustomItemFilterProxyModel(self)
self.proxy_model.setSourceModel(self.data_model)
self.setModel(self.proxy_model)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_1:
self.proxy_model.setFilterWildcard("*1*")
print self.proxy_model.filterRegExp()
if event.key() == QtCore.Qt.Key_2:
self.proxy_model.setFilterWildcard("*2*")
print self.proxy_model.filterRegExp()
if event.key() == QtCore.Qt.Key_3:
self.proxy_model.setFilterWildcard("*3*")
print self.proxy_model.filterRegExp()
if event.key() == QtCore.Qt.Key_Backspace:
self.proxy_model.setFilterFixedString("")
print self.proxy_model.filterRegExp()
if event.key() == QtCore.Qt.Key_Plus:
self.addNewItem()
QtGui.QListView.keyPressEvent(self, event)
def addNewItem(self):
item = CustomItem()
item.number = self.data_model.rowCount()
self.addItem(item)
def addItem(self, item):
self.data_model.appendRow(item)
proxy_index = self.proxy_model.mapFromSource(item.index())
self.setIndexWidget(proxy_index, item.item_widget)
if __name__ == '__main__':
import sys
qapplication = QtGui.QApplication(sys.argv)
layout = QtGui.QVBoxLayout()
window = QtGui.QDialog()
window.setLayout(layout)
view = CustomView(window)
view.resize(800, 600)
layout.addWidget(view)
for i in range(0, 10):
item = CustomItem()
item.number = i
view.addItem(item)
window.show()
sys.exit(qapplication.exec_())
or sample code here:
https://gist.github.com/66e29df303d1f1825a53
Can someone please help me on this? is this a known bug ? or I'm doing it completely wrong :P
Thanks in advance for your help.
This is an old question, but as I struggled with a similar problem for quite a while, here the solution I found and a possible explanation:
Instead of caching the custom widget on the model item, I cached the data needed to create the widget. In my case, I wanted to use a custom label with html in order to be able to format parts of text in different colour. Hence, I cached the html string on the item.
Then, in the initStyleOption method of the item delegate, I recreated the widget if it didn't yet exist or had disappeared after filtering:
label = self.parent().indexWidget(modelIndex)
if not label:
label = CustomLabel(item.html)
self.parent().setIndexWidget(modelIndex, label)
The reason why filtering deletes the widget cached on the item is as follows, I believe: the widget can "exist" only in one place. When it is put as indexWidget, it "exists" on a row in the view, not in an item of the model any more. As filtering removes rows from view, widgets on those rows get deleted. - A poor explanation, but I've often got similar surprises when manipulating html elements with JavaScript if I've forgotten to clone the element.