Форум сайта python.su
О! Я заставил таки данные в гриде изменяться под действием пользователя!
Данные из cu.fetchall() пришлось превратить из кортежа в список списков или кортеж списков (запутался я с ними).
Вот так:
# -*- coding: utf-8 -*-
import wx, wx.grid, sqlite3 as db
class MainFrame(wx.Frame):
def __init__(self, parent, title, pos, size):
wx.Frame.__init__(self, parent, -1, title, pos=pos, size=size)
mypanel=self.mypanel=wx.Panel(self, -1)
c=db.connect(database='bigbase.sqlite3')
cu=c.cursor()
cu.execute('SELECT fam, im, ot, age FROM one')
mygrid=wx.grid.Grid(mypanel, size=(400,400))
#—-вот таким страшным способом————
cuu=
for i in cu.fetchall():
tmp=
for ii in i:
tmp.append(ii)
cuu.append(tmp)
#—-делается список списков, который уже можно изменять
#—-обращаясь к нему как к массиву по индексам: cuu='новое значение'
#—-ОПУПЕТЬ! Почему создатели питона не хотят сделать обычный tuple изменяемым?????
#—-чтоб не приходилось так извращаться!
table=MyTable(cuu)
mygrid.SetTable(table, True)
class MyTable(wx.grid.PyGridTableBase):
def __init__(self, dannie):
wx.grid.PyGridTableBase.__init__(self)
self.dannie=dannie
def GetNumberRows(self):
return len(self.dannie)
pass
def GetNumberCols(self):
return len(self.dannie)
pass
def IsEmptyCell(self, row, col):
return self.dannie is not None
pass
def GetValue(self, row, col):
value = self.dannie
if value is not None:
return value
else:
return ''
pass
def SetValue(self, row, col, value):
self.dannie=value
pass
====================================
Кстати, ПроДива, в твоём примере, вновь занесённые данные в сетку, каждый раз ЗАНОВО добавляются к уже существующим в базе. А мне надо, чтобы в базу возвращались изменённые пользователем данные. Т.е. сменил пользователь в сетке кому-нибудь фамилию с “Пупкин” на “Губкин” и в базе этот конкретный “Пупкин” должен измениться на “Губкин”.
Вот как это сделать? Как узнать какое значение в сетке соответствует значению в базе sqlite? Чтобы можно было изменить его. Наверное, у записей в базе есть (да обязаны быть!) уникальные номера и следить нужно за ними. Как до них добраться? Без таких номеров, невозможно будет проконтролировать какую запись изменил пользователь. Я ведь могу в сетку выдать и отсортированный результат запроса, так что не факт, что данные в сетке расположатся в том же порядке, что и в базе.
Ламерский вопрос: какая sql-команда позволяет изменить какую-либо конкретную запись?
———————–
В твоём примере некорректно printится номер (столбца и строки) ячейки, если перед тем как щёлкнуть какую-нибудь ячейку воспользоваться бегунком прокрутки. Только повторный щёлк заставит появиться правильный номер.
———————–
Почему в гриде не работают клавиши end и home?
БОЛЬШОЕ СПАСИБО заранее.
Офлайн
строка:
cuu=
выполнит то же преобразование что и Ваш код (да и выглядит не очень страшно)
#—-вот таким страшным способом————
cuu=
for i in cu.fetchall():
tmp=
for ii in i:
tmp.append(ii)
cuu.append(tmp)
#—-делается список списков, который уже можно изменять
FoxPythonв идеале у каждой таблицы должно быть ключевое поле (primary, unique …)
… Как узнать какое значение в сетке соответствует значению в базе sqlite? Чтобы можно было изменить его. Наверное, у записей в базе есть (да обязаны быть!) уникальные номера и следить нужно за ними. Как до них добраться? Без таких номеров, невозможно будет проконтролировать какую запись изменил пользователь. Я ведь могу в сетку выдать и отсортированный результат запроса, так что не факт, что данные в сетке расположатся в том же порядке, что и в базе.
Ламерский вопрос: какая sql-команда позволяет изменить какую-либо конкретную запись?
Офлайн
Как же я привык к фокспро (рыдающий смайл)…
Но всё равно спасибо, будем продолжать пытаться…
—————-
Давит грузом неопределённости питон 3000. Сейчас изучу питон 2.5.1, а он больше не поддерживается и не развивается! Потом все программы перелопачивать на питон 3000?
Офлайн
А, вообще, как ещё, кроме моего способа, можно сунуть данные из базы в таблицу PyGridTableBase? Неужели только моим способом? Что-то не верится…
Офлайн
Ну вот вам еще один вариант
# -*- coding: utf-8 -*-
import wx
import wx.grid
from sqlite3 import dbapi2 as db
class BaseTable(wx.grid.PyGridTableBase):
def __init__(self, connection):
super(BaseTable, self).__init__()
self.connection = connection
self.refresh()
def field_list(self):
ls =
ls.extend()
return ls
def refresh(self):
cur = self.connection.cursor()
cur.execute(“select %s from %s;” % (','.join(self.field_list()), self.table))
self.data =
cur.close()
def save_value(self, row, col):
if self.data:
cur = self.connection.cursor()
cur.execute(“update %s set %s = ‘%s’ where %s = %s;” % (self.table,
self.columns.name, self.data, self.primary_key, self.data))
self.connection.commit()
cur.close()
def GetNumberRows(self):
return len(self.data)
def GetNumberCols(self):
return len(self.columns)
def GetColLabelValue(self, col):
return self.columns.title
def GetRowLabelValue(self, row):
return str(row)
def IsEmptyCell(self, row, col):
return self.data is not None
def GetValue(self, row, col):
return self.data
def SetValue(self, row, col, value):
if self.data != value:
self.data = value
self.save_value(row, col)
def InsertRows(self, pos=1, numRows=1):
cur = self.connection.cursor()
for n in range(pos, pos+numRows):
cur.execute(“insert into %s(%s) values(%s);” % (self.table, ‘,’.join(),
‘,’.join()))
ls =
ls.extend()
self.data.insert(n, ls)
self.connection.commit()
cur.close()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_INSERTED, pos, numRows)
self.GetView().ProcessTableMessage(msg)
return True
def DeleteRows(self, pos=0, numRows=1):
cur = self.connection.cursor()
for n in range(pos, pos+numRows):
cur.execute(“delete from %s where %s = %s;” % (self.table, self.primary_key, self.data))
self.connection.commit()
del self.data
cur.close()
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, pos, numRows)
self.GetView().ProcessTableMessage(msg)
return True
class Column(object):
def __init__(self, name, title, default=None):
self.name = name
self.title = title
self.default = default
class TestTable(BaseTable):
table = ‘test’
primary_key = ‘id’
columns = (
Column('numb', u'Табельный\nномер'),
Column('fio', u'ФИО', u'Иванов Иван Иваныч'),
Column('dolzh', u'Должность',u'Стрелочник'),
)
class SimpleGrid(wx.grid.Grid):
def __init__(self, parent, model):
super(SimpleGrid, self).__init__(parent, -1)
self.SetTable(model)
for col in range(0, self.GetNumberCols()):
self.AutoSizeColumn(col, setAsMin=True)
self.Bind(wx.EVT_KEY_DOWN, self.on_key_down)
def on_key_down(self, event):
if event.ControlDown() and event.KeyCode == wx.WXK_DELETE:
self.on_delete(event)
elif event.KeyCode == wx.WXK_INSERT:
self.on_insert(event)
event.Skip()
def on_insert(self, event):
print “on_insert”
self.InsertRows(self.GetGridCursorRow())
def on_delete(self, event):
print “on_delete”
self.DeleteRows(self.GetGridCursorRow())
def create_db(name):
con = db.connect(name)
cur = con.cursor()
try:
cur.execute(“”“
create table test (
id integer primary key autoincrement,
numb integer,
fio varchar(200),
dolzh varchar(200));
”“”)
for x in xrange(0, 500):
cur.execute(u“insert into test(numb, fio, dolzh) values(%d, ‘Сотрудник %d’, ‘Должность %d’)” % (x,x,x))
except db.DatabaseError, x:
print “Не могу создать базу!”, x
print “База создана!”
con.commit()
return con
class TestFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, “A Grid”, size=(500, 400))
grid = SimpleGrid(self, TestTable(create_db('test.db')))
if __name__ == ‘__main__’:
app = wx.PySimpleApp()
frame = TestFrame(None)
frame.Show(True)
app.MainLoop()
Только что набросал на коленке, но базовые моменты думаю будут понятны
Офлайн
Спасибо за пример. Счас буду по полочкам раскладывать.
———————————————————————-
Если, вдруг, кому охота ответить:
class Myclass():
a=1
b=2
——————————————–
class Myclass():
def __init__(self, tralivali):
self.a=1
self.b=2
Это что, получается, что метод __init__ не являются целиком и полностью принадлежностью класса Myclass? Ведь метод __init__ описан в самом этом классе. Логично же, что он относится ИМЕННО к нему. Зачем же иниту передавать self?
———————————————————————-
П.С. У Вас у всех в примерах после того как программа выдаст “не могу создать базу”, вдобавок напишет и “база создана”. Так низя! Дезинформация, понимашь!
Офлайн
FoxPython__init__ является целиком и полностью принадлежностью класса, а self указывает на обьект этого класса. :)
Это что, получается, что метод __init__ не являются целиком и полностью принадлежностью класса Myclass? Ведь метод __init__ описан в самом этом классе. Логично же, что он относится ИМЕННО к нему. Зачем же иниту передавать self?
Офлайн
FoxPythonНу а что ты хотел для простого примера?! Я просто взял код создания базы из предыдущего примера. В серьезных приложениях база обычно создается при установке.
П.С. У Вас у всех в примерах после того как программа выдаст “не могу создать базу”, вдобавок напишет и “база создана”. Так низя! Дезинформация, понимашь!
Отредактировано (Ноя. 22, 2007 07:29:26)
Офлайн
PooH, спасибо за последовательность действий и за код :)
PooHсогласен это очень хороший вариант, но только если не критична эффективность кода и данных не много (в основном ячеек). Если же таблицы большие или в записи есть большое поле, то лучше делать запросы на более низком уровне (например на sqlbuilder или да просто запросы на sql)
1. Лучше для работы с базой воспользоваться каким-нибудь готовым ОРМ, например SQLObject или SQLAlchemy. Тогда код BaseTable упрощается до безобразия
PooHдля экономии ОЗУ можно использовать временные файлы :)
3. Для большого набора данных лучше использовать буфер и прокручивать набор через него
Офлайн
pythonwinА здесь поможет lazy loading в ОРМ для больших полей.
Если же таблицы большие или в записи есть большое поле, то лучше делать запросы на более низком уровне (например на sqlbuilder или да просто запросы на sql)
pythonwinЗдесь речь не столько об экономии ОЗУ, сколько об экономии сетевого трафика :) Обычно никто не будет прокручивать в гриде набор из 1000 и более записей, а воспользуется поиском или фильтром. Так зачем это тянуть на клиента?!PooHдля экономии ОЗУ можно использовать временные файлы :)
3. Для большого набора данных лучше использовать буфер и прокручивать набор через него
Офлайн