Compare commits
10 Commits
59b55c1e0f
...
3937be3cb5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3937be3cb5 | ||
![]() |
77da13fbaa | ||
![]() |
8ca81184a9 | ||
![]() |
7bcca92697 | ||
![]() |
1e0950083e | ||
![]() |
4efc72e071 | ||
![]() |
9904d5b4e9 | ||
![]() |
9cc5c6cd57 | ||
![]() |
c6a63b972e | ||
![]() |
b2de966586 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
__pycache__/
|
42
README.md
42
README.md
@ -1 +1,41 @@
|
||||
Это зачаток программы управления данными на основе описания структуры в json формате.
|
||||
# Это зачаток программы управления данными на основе описания структуры в json формате.
|
||||
Пишется на python3 в качестве графической библиотеки Qt5.
|
||||
|
||||
# Использование
|
||||
|
||||
По умолчанию используется шаблон и БД 'dm'. Для того чтобы изменить БД, создаем JSON шаблон согласно описания (см. примеры в db_template).
|
||||
|
||||
Затем данный файл нужно скопировать в '~/.dm/db_template/', следущим шагом меняем в конфиге 'dm.cfg' имя БД на имя вашего шаблона без расширения json, т.е. к примеру для работы с книжным каталогом (файл db_template/library.json) файл настроек будет выглядеть следующим оюбразом:
|
||||
|
||||
```
|
||||
[DataBase]
|
||||
db_type = sqlite
|
||||
db_hostname = localhost
|
||||
db_name = library
|
||||
db_user = dm
|
||||
db_password = password
|
||||
|
||||
[Directory]
|
||||
work_dir = /home/svkalinin/.dm
|
||||
template_dir = /home/svkalinin/.dm/db_template
|
||||
|
||||
```
|
||||
|
||||
После этого можно запустить программу, при первом запуске будет создана БД согласно шаблона:
|
||||
|
||||
```
|
||||
python3 gui.py
|
||||
```
|
||||
|
||||
# СУБД
|
||||
|
||||
Пока реализована работа с Mysql (или Mariadb) и sqlite (по умолчанию). Для из менения типа БД в конфиге меняем 'dbtype':
|
||||
|
||||
```
|
||||
dbtype = sqlite
|
||||
|
||||
или
|
||||
|
||||
dbtype = mysql
|
||||
```
|
||||
|
||||
|
BIN
__pycache__/dm.cpython-36.pyc
Normal file
BIN
__pycache__/dm.cpython-36.pyc
Normal file
Binary file not shown.
@ -6,8 +6,8 @@
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "int(6)",
|
||||
"fDescription": "UID",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
@ -60,8 +60,8 @@
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "int(6)",
|
||||
"fDescription": "UID",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
@ -85,7 +85,7 @@
|
||||
{
|
||||
"fName": "users_id",
|
||||
"fDescription": "Владелец",
|
||||
"fType": "int(6)",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["users.id", "last_name, name, middle_name"]
|
||||
@ -93,7 +93,7 @@
|
||||
{
|
||||
"fName": "parent_id",
|
||||
"fDescription": "Родительский документ",
|
||||
"fType": "int(6)",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["docs.id", "doc_name"]
|
||||
@ -106,8 +106,8 @@
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "int(6)",
|
||||
"fDescription": "UID",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
@ -122,7 +122,7 @@
|
||||
},
|
||||
{
|
||||
"fName": "city",
|
||||
"fDescription": "Населеннй пункт",
|
||||
"fDescription": "Населенный пункт",
|
||||
"fType": "varchar(200)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
@ -147,54 +147,116 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "test",
|
||||
"tableDescription": "Шляпа",
|
||||
"tableName": "items",
|
||||
"tableDescription": "Оборудование",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "int(11)",
|
||||
"fDescription": "UID",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "user",
|
||||
"fDescription": "Юзер шляпы",
|
||||
"fType": "int(11)",
|
||||
"fName": "item_name",
|
||||
"fDescription": "Наименование",
|
||||
"fType": "VARCHAR(100)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["users.id", "last_name, name, middle_name"]
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "item_address",
|
||||
"fDescription": "Место расположения",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["address.id", "city, street, house"]
|
||||
},
|
||||
{
|
||||
"fName": "item_type",
|
||||
"fDescription": "Тип",
|
||||
"fType": "CHAR(20)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["itemtype.id", "type_name"]
|
||||
},
|
||||
{
|
||||
"fName": "inventory_number",
|
||||
"fDescription": "Инвентарный номер",
|
||||
"fType": "CHAR(10)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "test2",
|
||||
"tableDescription": "Шляпа2",
|
||||
"tableName": "itemtype",
|
||||
"tableDescription": "Тип оборудования",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "int(11)",
|
||||
"fDescription": "UID",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "ins_date",
|
||||
"fDescription": "Дата добавления",
|
||||
"fName": "type_name",
|
||||
"fDescription": "Тип",
|
||||
"fType": "VARCHAR(100)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "itemrelocation",
|
||||
"tableDescription": "Перемещения",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "UID",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "item_id",
|
||||
"fDescription": "Оборудование",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["items.id", "item_name, inventory_number"]
|
||||
},
|
||||
{
|
||||
"fName": "source_place",
|
||||
"fDescription": "Откуда",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["address.id", "city, street, house"]
|
||||
},
|
||||
{
|
||||
"fName": "destination_place",
|
||||
"fDescription": "Куда",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["address.id", "city, street, house"]
|
||||
},
|
||||
{
|
||||
"fName": "create_datetime",
|
||||
"fDescription": "Дата перемещения",
|
||||
"fType": "DATETIME",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "user",
|
||||
"fDescription": "Юзер шляпы",
|
||||
"fType": "int(11)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["users.id", "last_name, name, middle_name"]
|
||||
}
|
||||
]
|
||||
}
|
141
db_template/library.json
Normal file
141
db_template/library.json
Normal file
@ -0,0 +1,141 @@
|
||||
{
|
||||
"tables": [
|
||||
{
|
||||
"tableName": "publisher",
|
||||
"tableDescription": "Издательство",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "publisher_name",
|
||||
"fDescription": "Наименование",
|
||||
"fType": "char(20)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "authors",
|
||||
"tableDescription": "Авторы",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "last_name",
|
||||
"fDescription": "Фамилия",
|
||||
"fType": "char(20)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "name",
|
||||
"fDescription": "Имя",
|
||||
"fType": "char(20)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "middle_name",
|
||||
"fDescription": "Отчество",
|
||||
"fType": "char(20)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "books",
|
||||
"tableDescription": "Книги",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "book_name",
|
||||
"fDescription": "Название",
|
||||
"fType": "varchar(100)",
|
||||
"index": "yes",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "description",
|
||||
"fDescription": "Описание",
|
||||
"fType": "varchar(200)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "authors_id",
|
||||
"fDescription": "Автор",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["authors.id", "last_name, name, middle_name"]
|
||||
},
|
||||
{
|
||||
"fName": "publisher_id",
|
||||
"fDescription": "Издательство",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["publisher.id", "publisher_name"]
|
||||
},
|
||||
{
|
||||
"fName": "category_id",
|
||||
"fDescription": "Жанр",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["category.id", "category_name"]
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "category",
|
||||
"tableDescription": "Жанр",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "category_name",
|
||||
"fDescription": "Название жанра",
|
||||
"fType": "varchar(100)",
|
||||
"index": "yes",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
72
db_template/radio-catalog.json
Normal file
72
db_template/radio-catalog.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"tables": [
|
||||
{
|
||||
"tableName": "type",
|
||||
"tableDescription": "Тип элемента",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "INT(6)",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "name",
|
||||
"fDescription": "Тип элемента",
|
||||
"fType": "char(20)",
|
||||
"index": "yes",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "items",
|
||||
"tableDescription": "Элементы",
|
||||
"fieldList": [
|
||||
{
|
||||
"fName": "id",
|
||||
"fDescription": "Номер п.п.",
|
||||
"fType": "INTEGER",
|
||||
"index": "PRIMARY KEY",
|
||||
"autoIncrement": "yes",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "item_name",
|
||||
"fDescription": "Наименование",
|
||||
"fType": "varchar(100)",
|
||||
"index": "yes",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "description",
|
||||
"fDescription": "Описание",
|
||||
"fType": "varchar(200)",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
},
|
||||
{
|
||||
"fName": "type_id",
|
||||
"fDescription": "Тип",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": ["type.id", "name"]
|
||||
},
|
||||
{
|
||||
"fName": "count",
|
||||
"fDescription": "Количество",
|
||||
"fType": "INTEGER",
|
||||
"index": "no",
|
||||
"autoIncrement": "no",
|
||||
"relation": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
129
dm.py
129
dm.py
@ -3,8 +3,8 @@ import json, os, configparser, shutil, re
|
||||
from datetime import datetime, date, time
|
||||
|
||||
def firstInit():
|
||||
# Инициализация переменныхб создание конфигруационного файла, копирование шаблонов
|
||||
global db_type, db_hostname, db_user, db_password, db_name, template_file, db_type
|
||||
# Инициализация переменных создание конфигруационного файла, копирование шаблонов
|
||||
global db_type, db_hostname, db_user, db_password, db_name, template_file, db_type, template_dir
|
||||
config = configparser.RawConfigParser()
|
||||
# проверяем тип ОС
|
||||
if os.name == "nt":
|
||||
@ -19,7 +19,7 @@ def firstInit():
|
||||
cfg_file = os.path.join(cfg_dir, 'dm.cfg')
|
||||
# создадим файл конфигурации
|
||||
config.add_section('DataBase')
|
||||
config.set('DataBase', 'db_type', 'mysql')
|
||||
config.set('DataBase', 'db_type', 'sqlite')
|
||||
config.set('DataBase', 'db_hostname', 'localhost')
|
||||
config.set('DataBase', 'db_name', 'dm')
|
||||
config.set('DataBase', 'db_user', 'dm')
|
||||
@ -39,6 +39,7 @@ def firstInit():
|
||||
config.read(cfg_file)
|
||||
|
||||
work_dir = config.get('Directory', 'work_dir')
|
||||
global template_dir
|
||||
template_dir = config.get('Directory', 'template_dir')
|
||||
db_type = config.get('DataBase', 'db_type')
|
||||
db_hostname = config.get('DataBase', 'db_hostname')
|
||||
@ -59,11 +60,13 @@ def firstInit():
|
||||
else:
|
||||
os.mkdir(template_dir)
|
||||
# копируем и читаем файл шаблон БД
|
||||
template_file = os.path.join(template_dir, 'tables.json')
|
||||
template = config.get('DataBase', 'db_name') + '.json'
|
||||
|
||||
template_file = os.path.join(template_dir, template)
|
||||
if os.path.isfile(template_file):
|
||||
print("Template file already exists")
|
||||
print("Template file already exists " + template_file)
|
||||
else:
|
||||
shutil.copy('tables.json', template_file)
|
||||
shutil.copy('db_template/dm.json', template_file)
|
||||
|
||||
|
||||
def dbConnect():
|
||||
@ -167,17 +170,18 @@ def createTables(tbl_list):
|
||||
i = i + 1
|
||||
dbTablesDescriptionList.append(one_Table_descr)
|
||||
dbTablesStructList.append(one_Table_struct)
|
||||
#print(qwery_create)
|
||||
print(qwery_create)
|
||||
c.execute(qwery_create)
|
||||
return dbTablesNamesList
|
||||
|
||||
def initDBstructure():
|
||||
global dbTablesDescriptionList, template_file, tblNamesList
|
||||
table_list = open(template_file, "r", encoding="utf-8")
|
||||
data = json.load(table_list, encoding="utf-8")
|
||||
tbl_list = data["tables"]
|
||||
tblNamesList = createTables(tbl_list)
|
||||
|
||||
# data = json.load(table_list, encoding="utf-8")
|
||||
data = json.load(table_list)
|
||||
#tbl_list = data["tables"]
|
||||
#tblNamesList = createTables(tbl_list)
|
||||
tblNamesList = createTables(data["tables"])
|
||||
return tblNamesList
|
||||
|
||||
# выборка данных из заданной таблицы
|
||||
@ -186,6 +190,7 @@ def selectData(tbl):
|
||||
# если юольше 1 поля добавить CONCAT
|
||||
qwery = "SELECT "
|
||||
subqwery = ""
|
||||
#print(dbTablesStructList)
|
||||
for item in dbTablesStructList:
|
||||
if item[0] == tbl:
|
||||
for field in item[1]:
|
||||
@ -204,20 +209,17 @@ def selectData(tbl):
|
||||
else:
|
||||
subqwery = table1
|
||||
# составляем подзапрос и подменяем им поле в запросе
|
||||
print(subqwery)
|
||||
|
||||
if db_type == "mysql":
|
||||
field_replace = field_replace.replace(",", ",' ',")
|
||||
#subqwery = "(SELECT CONCAT(" + field_replace + ") FROM " + subqwery + " WHERE " + table1 + "." + field1 + "=" + tbl + "." + field + ") AS " + field
|
||||
# subqwery = "(SELECT CONCAT({}) FROM {} WHERE {}.{}={}.{}) AS {}"\
|
||||
# .format(field_replace,subqwery,table1,field1,tbl,field,field)
|
||||
subqwery = "(SELECT CONCAT('>', {}, '<', {}) FROM {} WHERE {}.{}={}.{}) AS {}"\
|
||||
.format(field,field_replace,subqwery,table1,field1,tbl,field,field)
|
||||
subqwery = "(SELECT CONCAT('>', {}.{}, '<', {}) FROM {} WHERE {}.{}={}.{}) AS {}"\
|
||||
.format(tbl,field,field_replace,subqwery,table1,field1,tbl,field,field)
|
||||
elif db_type == "sqlite":
|
||||
field_replace = field_replace.replace(",", " || ' ' ||")
|
||||
#subqwery = "(SELECT (" + field_replace + ") FROM " + subqwery +" WHERE "+ table1 + "." + field1 +"="+ tbl +"."+ field +") AS " + field
|
||||
subqwery = "(SELECT ({}) FROM {} WHERE {}.{}={}.{}) AS {}" \
|
||||
.format(field_replace, subqwery, table1, field1, tbl, field, field)
|
||||
qwery = qwery.replace(field, subqwery)
|
||||
#qwery = qwery.rstrip(',') + " FROM " + tbl + " LIMIT 10000"
|
||||
qwery = '{} FROM {} LIMIT 10000'.format(qwery.rstrip(','), tbl)
|
||||
print(qwery)
|
||||
c.execute(qwery)
|
||||
@ -226,8 +228,6 @@ def selectData(tbl):
|
||||
# получаем на вход имя таблицы и возвращаем список заголовков полей
|
||||
def getTableStructure(tbl):
|
||||
global dbTablesDescriptionList, dbTablesStructList
|
||||
#print(dbTablesDescriptionList)
|
||||
#print(dbTablesStructList)
|
||||
for item in dbTablesDescriptionList:
|
||||
if item[0] == tbl:
|
||||
return item[1]
|
||||
@ -235,8 +235,6 @@ def getTableStructure(tbl):
|
||||
# Получаем список названий полей и типов для заданной таблицы
|
||||
def getFields(tbl):
|
||||
global dbTablesDescriptionList, dbTablesStructList
|
||||
#print(dbTablesDescriptionList)
|
||||
#print(dbTablesStructList)
|
||||
for item in dbTablesStructList:
|
||||
if item[0] == tbl:
|
||||
#print(item[1])
|
||||
@ -256,7 +254,7 @@ def fieldTypeConvert(ftype):
|
||||
# разбираем строку на тип и длину
|
||||
ftype = str.lower(ftype)
|
||||
line = re.search("(.+?)\(([0-9]+)\)", ftype)
|
||||
if line:
|
||||
if line:
|
||||
fType = line.groups()[0]
|
||||
fLength = line.groups()[1]
|
||||
if fType == 'int' or fType == 'integer':
|
||||
@ -265,26 +263,20 @@ def fieldTypeConvert(ftype):
|
||||
fType = 'character'
|
||||
else:
|
||||
fType = ftype
|
||||
#print(fType)
|
||||
return fType
|
||||
|
||||
def getFieldType(tbl, field):
|
||||
global dbTablesDescriptionList, dbTablesStructList
|
||||
#print(dbTablesDescriptionList)
|
||||
#print(dbTablesStructList)
|
||||
for item in dbTablesStructList:
|
||||
if item[0] == tbl:
|
||||
for i in item[1]:
|
||||
if i[0] == field:
|
||||
fType = i[1]
|
||||
return fType
|
||||
#print(item[1])
|
||||
#return item[1]
|
||||
|
||||
def getRelationsForField(tblSearch, fieldName):
|
||||
global dbTablesStructList, c, db_type
|
||||
#print("Ищем связи для:" +tblSearch +','+ fieldName)
|
||||
#print(dbTablesStructList)
|
||||
#searchField = tblSearch + '.' + fieldName
|
||||
dataList = []
|
||||
for item in dbTablesStructList:
|
||||
#print(item)
|
||||
@ -295,16 +287,10 @@ def getRelationsForField(tblSearch, fieldName):
|
||||
if tblName == tblSearch:
|
||||
# выдергиваем из списка название и поле нужной нам таблицы
|
||||
if rel[0] == fieldName:
|
||||
#print('table - ' + tblName)
|
||||
##print('field - ' + fieldName)
|
||||
#print('relation - ' + str(rel))
|
||||
l = rel[1][0].split('.')
|
||||
relTable = l[0]
|
||||
relField = l[1]
|
||||
replaceFields = rel[1][1]
|
||||
# print('reltable - ' + relTable)
|
||||
#print('relfield - ' + relField)
|
||||
#print('relrelation - ' + replaceFields)
|
||||
return [relTable, relField, replaceFields]
|
||||
return "q"
|
||||
|
||||
@ -314,10 +300,6 @@ def insertDataIntoBD(dataList):
|
||||
global c, conn
|
||||
dbConnect()
|
||||
tableName = dataList[0]
|
||||
#print(dataList)
|
||||
#datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")
|
||||
|
||||
#qwery = 'INSERT INTO ' + tableName + ' ('
|
||||
qwery = 'INSERT INTO {} ('.format(tableName)
|
||||
qweryData = ''
|
||||
qweryField = ''
|
||||
@ -326,30 +308,23 @@ def insertDataIntoBD(dataList):
|
||||
#print(fType)
|
||||
# проверяем если значение поля пустое то в запрос оно не включается
|
||||
if item[1] != '':
|
||||
#qweryField = qweryField + item[0] + ','
|
||||
qweryField = '{}{},'.format(qweryField,item[0])
|
||||
if fType == 'integer':
|
||||
#qweryData = qweryData + '' + item[1] + ','
|
||||
qweryData = '{}{},'.format(qweryData,item[1])
|
||||
elif fType == 'datetime':
|
||||
# преобразуем дату всяко разно
|
||||
dt = datetime.strptime(item[1], "%d.%m.%y %H:%M")
|
||||
item[1] = str(dt)
|
||||
#qweryData = qweryData + '\'' + item[1] + '\','
|
||||
qweryData = "{}'{}',".format(qweryData,item[1])
|
||||
elif fType == 'date':
|
||||
d = item[1].split('.')
|
||||
#myDate = d[2] + '-' + d[1] + '-' + d[1]
|
||||
myDate = '{}-{}-{}'.format(d[2], d[1], d[1])
|
||||
item[1] = str(myDate)
|
||||
#qweryData = qweryData + '\'' + item[1] + '\','
|
||||
qweryData = "{}'{}',".format(qweryData, item[1])
|
||||
else:
|
||||
#qweryData = qweryData + '\'' + item[1] + '\','
|
||||
qweryData = "{}'{}',".format(qweryData, item[1])
|
||||
|
||||
|
||||
#qwery = qwery + qweryField.rstrip(',') + ')' + ' VALUES (' + qweryData.rstrip(',') + ');'
|
||||
qwery = '{}{}) VALUES ({});'.format(qwery, qweryField.rstrip(','), qweryData.rstrip(','))
|
||||
|
||||
print(qwery)
|
||||
@ -385,20 +360,16 @@ def selectDataFromDB(tblName, fieldName, fieldValue):
|
||||
# составляем подзапрос и подменяем им поле в запросе
|
||||
if db_type == "mysql":
|
||||
fieldReplace = fieldReplace.replace(",", ",' ',")
|
||||
#subqwery = "(SELECT CONCAT(" + fieldReplace + ") FROM " + subqwery + " WHERE " + table1 + "." + field1 + "=" + tblName + "." + field + ") AS " + field
|
||||
subqwery = '(SELECT CONCAT({}) FROM {} WHERE {}.{}={}.{}) AS {}'\
|
||||
.format(fieldReplace, subqwery, table1, field1, tblName, field, field)
|
||||
elif db_type == "sqlite":
|
||||
fieldReplace = fieldReplace.replace(",", " || ' ' ||")
|
||||
#subqwery = "(SELECT (" + fieldReplace + ") FROM " + subqwery +" WHERE "+ table1 + "." + field1 +"="+ tblName +"."+ field +") AS " + field
|
||||
subqwery = '(SELECT ({}) FROM {} WHERE {}.{}={}.{}) AS {}'\
|
||||
.format(fieldReplace, subqwery, table1, field1, tblName, field, field)
|
||||
#print("---" + subqwery)
|
||||
qwery = qwery.replace(field, subqwery)
|
||||
#qwery = qwery.rstrip(',') + " FROM " + tblName + " LIMIT 10000"
|
||||
#qwery = qwery.rstrip(',') + " FROM " + tblName + " WHERE " + fieldName + '=' + fieldValue
|
||||
qwery = '{} FROM {} WHERE {}={}'.format(qwery.rstrip(','), tblName, fieldName, fieldValue)
|
||||
|
||||
|
||||
print(qwery)
|
||||
c.execute(qwery)
|
||||
return c.fetchall()
|
||||
@ -435,11 +406,11 @@ def getTablesDescriptionOfName(tblName):
|
||||
def deleteRecordsFromDB(tableName, valueList):
|
||||
global c, db_type, conn
|
||||
qwery = 'DELETE FROM {} WHERE '.format(tableName)
|
||||
#print(qwery)
|
||||
#print(valueList)
|
||||
subQwery=''
|
||||
i = 0
|
||||
for item in getFields(tableName):
|
||||
print(item[0], item[1])
|
||||
#print(item[0], item[1])
|
||||
if item[1] == 'integer':
|
||||
#subQwery = subQwery + item[0] + '=' + valueList[i] + ' AND '
|
||||
subQwery = '{}{}={} AND '.format(subQwery, item[0], valueList[i])
|
||||
@ -449,11 +420,61 @@ def deleteRecordsFromDB(tableName, valueList):
|
||||
i += 1
|
||||
qwery += subQwery
|
||||
qwery = qwery.rstrip('AND ').replace("='None'", " IS NULL")
|
||||
qwery = qwery.rstrip('AND ').replace("=None", " IS NULL")
|
||||
qwery = qwery.rstrip('AND ').replace("=NULL", " IS NULL")
|
||||
print(qwery)
|
||||
c.execute(qwery)
|
||||
conn.commit()
|
||||
return
|
||||
|
||||
# Редактирование записи в БД
|
||||
def editDataIntoBD(dataList):
|
||||
global c, conn
|
||||
dbConnect()
|
||||
tableName = dataList[0]
|
||||
qwery = 'UPDATE {} SET '.format(tableName)
|
||||
#qweryData = ''
|
||||
qweryField = ''
|
||||
qweryWhere = ''
|
||||
for item in dataList[1]:
|
||||
fType = getFieldType(tableName, item[0])
|
||||
# проверяем если значение поля пустое то в запрос оно не включается
|
||||
if item[1] != '':
|
||||
qweryField = '{}{}='.format(qweryField,item[0])
|
||||
|
||||
if fType == 'integer':
|
||||
qweryField = '{}{},'.format(qweryField,item[1])
|
||||
elif fType == 'datetime':
|
||||
# преобразуем дату всяко разно
|
||||
dt = datetime.strptime(item[1], "%d.%m.%y %H:%M")
|
||||
item[1] = str(dt)
|
||||
qweryField = "{}'{}',".format(qweryField,item[1])
|
||||
elif fType == 'date':
|
||||
d = item[1].split('.')
|
||||
myDate = '{}-{}-{}'.format(d[2], d[1], d[1])
|
||||
item[1] = str(myDate)
|
||||
qweryField = "{}'{}',".format(qweryField, item[1])
|
||||
else:
|
||||
qweryField = "{}'{}',".format(qweryField, item[1])
|
||||
qwery = '{}{} WHERE {};'.format(qwery, qweryField.rstrip(','), qweryWhere)
|
||||
|
||||
print(qwery)
|
||||
#c.execute(qwery)
|
||||
#conn.commit()
|
||||
#c.close()
|
||||
return
|
||||
# Вывод структуры таблицы из базы данных
|
||||
def getTableStructureFromDB(tableName):
|
||||
global c, db_type, conn
|
||||
|
||||
if db_type == 'sqlite':
|
||||
qwery = 'PRAGMA table_info({})'.format(tableName)
|
||||
fieldsList = c.execute(qwery).fetchall()
|
||||
#for row in fieldsList:
|
||||
# print(row)
|
||||
return(fieldsList)
|
||||
|
||||
|
||||
#initDBstructure()
|
||||
firstInit()
|
||||
dbConnect()
|
||||
|
154
gui.py
Normal file → Executable file
154
gui.py
Normal file → Executable file
@ -5,6 +5,8 @@ import sys
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
#from PyQt5.QtWidgets import (QMainWindow, QTextEdit, QAction, QFileDialog, QApplication)
|
||||
#from PyQt5.QtGui import QIcon
|
||||
|
||||
#import pymysql
|
||||
import dm
|
||||
@ -33,6 +35,7 @@ class MyTable(QTableWidget):
|
||||
def contextMenuEvent(self, event):
|
||||
Rmenu = QMenu(self)
|
||||
addRecord = Rmenu.addAction("Добавить запись")
|
||||
editRecord = Rmenu.addAction("Редактировать запись")
|
||||
delRecord = Rmenu.addAction("Удалить запись")
|
||||
showRelations = Rmenu.addAction("Показать связанные документы")
|
||||
action = Rmenu.exec_(self.mapToGlobal(event.pos()))
|
||||
@ -46,6 +49,13 @@ class MyTable(QTableWidget):
|
||||
elif action == addRecord:
|
||||
print("Добавить запись ")
|
||||
addNewRecord()
|
||||
elif action == editRecord:
|
||||
row = self.rowAt(event.pos().y())
|
||||
col = self.columnAt(event.pos().x())
|
||||
#print("Удаляем row:%d, col:%d" % (row, col))
|
||||
item = self.item(self.currentIndex().row(), self.currentIndex().column())
|
||||
print("Редактировать запись ")
|
||||
self.editCurrentRecord(row)
|
||||
elif action == showRelations:
|
||||
item = self.item(self.currentIndex().row(), self.currentIndex().column())
|
||||
showRelationsRecords(self.currentIndex().column(), item.text())
|
||||
@ -69,6 +79,24 @@ class MyTable(QTableWidget):
|
||||
#print(self.item(row, i).text())
|
||||
i += 1
|
||||
deleteRecord(self, row, self.dbTableName, valueList)
|
||||
# редактирование записи
|
||||
def editCurrentRecord(self, row):
|
||||
valueList = []
|
||||
#print(self.dbTableName, row, self.statusTip())
|
||||
i = 0
|
||||
#print(self.columnCount())
|
||||
#print(self.verticalHeaderItem(row).text(), '---')
|
||||
while i < self.columnCount():
|
||||
if self.item(row, i):
|
||||
val = self.item(row, i).text()
|
||||
print(val)
|
||||
valueList.append(str(val))
|
||||
else:
|
||||
valueList.append('')
|
||||
|
||||
i += 1
|
||||
print(valueList)
|
||||
editRecord(self, row, self.dbTableName, valueList)
|
||||
|
||||
# Диалог выбора связанных данных
|
||||
class RelationDataView(QMainWindow):
|
||||
@ -170,10 +198,14 @@ class EditForm(QMainWindow):
|
||||
lblList = []
|
||||
editList = []
|
||||
|
||||
def __init__(self, tblName, tblDescr):
|
||||
def __init__(self, tblName, tblDescr, action):
|
||||
super().__init__()
|
||||
self.tblName = tblName
|
||||
self.setWindowTitle("Добавление записи")
|
||||
self.action = action
|
||||
if action == 'edit':
|
||||
self.setWindowTitle("Редактирование записи")
|
||||
elif action == 'add':
|
||||
self.setWindowTitle("Добавление записи")
|
||||
#self.setGeometry(300, 300, 400, 400)
|
||||
scroll_widget = QWidget()
|
||||
self.general_layout = QVBoxLayout()
|
||||
@ -240,6 +272,7 @@ class EditForm(QMainWindow):
|
||||
edit.setValidator(integerValidator)
|
||||
else:
|
||||
edit = QLineEdit()
|
||||
|
||||
# создаём список полей и соответсвующих им QEdit
|
||||
self.widgetsList.append([fName, edit])
|
||||
|
||||
@ -247,15 +280,15 @@ class EditForm(QMainWindow):
|
||||
hboxEdit.addWidget(lbl2)
|
||||
hboxEdit.addWidget(edit)
|
||||
# добавляем к полю кнопку для вызова связанных
|
||||
print(fName)
|
||||
#print(fName)
|
||||
listRelationTableAndField = dm.getRelationsForField(tblName, fName)
|
||||
|
||||
print(listRelationTableAndField)
|
||||
#print(listRelationTableAndField)
|
||||
if listRelationTableAndField != 'q':
|
||||
tableRelation = listRelationTableAndField[0]
|
||||
fieldRelation = listRelationTableAndField[1]
|
||||
replaceField = listRelationTableAndField[2]
|
||||
print(tableRelation + '-' + fieldRelation +'-'+replaceField)
|
||||
#print(tableRelation + '-' + fieldRelation +'-'+replaceField)
|
||||
btnRelations = QPushButton('...')
|
||||
btnRelations.setFixedWidth(30)
|
||||
# добавляем название виджета в список соответсвия кнопок и таблиц БД
|
||||
@ -284,7 +317,10 @@ class EditForm(QMainWindow):
|
||||
listFieldData.append([item[0], item[1].text()])
|
||||
listData.append(listFieldData)
|
||||
#print(listData)
|
||||
dm.insertDataIntoBD(listData)
|
||||
if self.action == 'add':
|
||||
dm.insertDataIntoBD(listData)
|
||||
elif self.action == 'edit':
|
||||
dm.editDataIntoBD(listData)
|
||||
self.close()
|
||||
# выбираем данные для связанной таблицы
|
||||
def openRelationTable(self):
|
||||
@ -356,29 +392,38 @@ def addDataIntoTable(dbTableName, tblDataWidget, data='NULL'):
|
||||
dbFieldRelationValueList = []
|
||||
for key in data:
|
||||
n = 0
|
||||
#print(fieldNames, '\n', key)
|
||||
print(key)
|
||||
for item in key:
|
||||
#print(m, n, item)
|
||||
listRelationTableAndField = dm.getRelationsForField(dbTableName, fieldNames[n][0])
|
||||
#print('--->', fieldNames[n][1])
|
||||
if listRelationTableAndField != 'q':
|
||||
#print('yahooooo', fieldNames[n][0])
|
||||
itemString = dm.re.search('>([0-9])+<(.+)', str(item))
|
||||
# кривой алгоритм, надо придумывать что-то другое
|
||||
itemString = dm.re.search('>([0-9]+)<(.+)', str(item))
|
||||
if itemString:
|
||||
#print('--->',itemString.groups())
|
||||
newitem = QTableWidgetItem(itemString.groups()[1])
|
||||
dbFieldRelationValueList.append([newitem, m, n, itemString.groups()[0], itemString.groups()[1]])
|
||||
|
||||
else:
|
||||
newitem = QTableWidgetItem(str(item))
|
||||
dbFieldRelationValueList.append([newitem, m, n, 'None', 'None'])
|
||||
else:
|
||||
# преобразуем все типы в строку
|
||||
newitem = QTableWidgetItem(str(item))
|
||||
|
||||
# преобразуем все типы в строку
|
||||
#print(fieldNames[n][0])
|
||||
#print(str(item))
|
||||
# проверяем название поля и если это id то данные вносим в заголовок строки
|
||||
# таким образом внесем уникальный ID в чётко определенное поле
|
||||
#if fieldNames[n][0] == "id":
|
||||
# tblDataWidget.setVerticalHeaderItem(m, QTableWidgetItem(str(item)))
|
||||
tblDataWidget.setItem(m, n, newitem)
|
||||
n += 1
|
||||
m += 1
|
||||
#print(dbFieldRelationValueList)
|
||||
# Показ менб и панели инструментов
|
||||
|
||||
# Показ меню и панели инструментов
|
||||
def showMenuToolbar(window):
|
||||
openFileAction = QAction(QIcon('img/open.gif'), 'Открыть', window)
|
||||
openFileAction.setShortcut('Ctrl+O')
|
||||
openFileAction.setStatusTip('Открыть')
|
||||
openFileAction.triggered.connect(openTemplate)
|
||||
|
||||
newAction = QAction(QIcon('img/new.gif'), 'Добавить', window)
|
||||
newAction.setShortcut('Ins')
|
||||
newAction.setStatusTip('Добавить')
|
||||
@ -387,45 +432,46 @@ def showMenuToolbar(window):
|
||||
deleteAction = QAction(QIcon('img/delete.gif'), 'Удалить', window)
|
||||
deleteAction.setShortcut('Del')
|
||||
deleteAction.setStatusTip('Удалить')
|
||||
# deleteAction.triggered.connect(window.qqqq)
|
||||
|
||||
exitAction = QAction(QIcon('img/exit.gif'), 'Выход', window)
|
||||
exitAction.setShortcut('Ctrl+Q')
|
||||
exitAction.setStatusTip('Выход')
|
||||
exitAction.triggered.connect(window.close)
|
||||
exitAction.setStatusTip('Выйти')
|
||||
exitAction.triggered.connect(exit)
|
||||
|
||||
structureAction = QAction(QIcon('img/table.gif'), 'Показать структуру', window)
|
||||
#structureAction.setShortcut('Ctrl+Q')
|
||||
structureAction.setStatusTip('Показать структуру')
|
||||
structureAction.triggered.connect(showStructure)
|
||||
|
||||
cutAction = QAction(QIcon('img/cut.gif'), 'Вырезать', window)
|
||||
cutAction.setShortcut('Ctrl+X')
|
||||
cutAction.setStatusTip('Вырезать')
|
||||
# cutAction.triggered.connect(window.close)
|
||||
|
||||
copyAction = QAction(QIcon('img/copy.gif'), 'Копировать', window)
|
||||
copyAction.setShortcut('Ctrl+С')
|
||||
copyAction.setStatusTip('Копировать')
|
||||
# copyAction.triggered.connect(window.close)
|
||||
|
||||
pasteAction = QAction(QIcon('img/paste.gif'), 'Вставить', window)
|
||||
pasteAction.setShortcut('Ctrl+V')
|
||||
pasteAction.setStatusTip('Вставить')
|
||||
# pasteAction.triggered.connect(window.close)
|
||||
|
||||
findAction = QAction(QIcon('img/find.gif'), 'Копировать', window)
|
||||
findAction = QAction(QIcon('img/find.gif'), 'Поиск', window)
|
||||
findAction.setShortcut('Ctrl+F')
|
||||
findAction.setStatusTip('Искать')
|
||||
# findAction.triggered.connect(window.close)
|
||||
|
||||
printAction = QAction(QIcon('img/print.gif'), 'Печатать', window)
|
||||
printAction.setShortcut('Ctrl+P')
|
||||
printAction.setStatusTip('Печатать')
|
||||
# printAction.triggered.connect(window.close)
|
||||
|
||||
window.statusBar()
|
||||
|
||||
menubar = window.menuBar()
|
||||
fileMenu = menubar.addMenu('&Файл')
|
||||
fileMenu.addAction(openFileAction)
|
||||
fileMenu.addAction(newAction)
|
||||
fileMenu.addAction(deleteAction)
|
||||
fileMenu.addAction(printAction)
|
||||
fileMenu.addAction(structureAction)
|
||||
fileMenu.addAction(exitAction)
|
||||
|
||||
editMenu = menubar.addMenu('&Редактирование')
|
||||
@ -439,6 +485,7 @@ def showMenuToolbar(window):
|
||||
# toolbar = window.addToolBar('Редактирование')
|
||||
|
||||
toolbar = window.addToolBar('Панель инструментов')
|
||||
#toolbar.addAction(openFileAction)
|
||||
toolbar.addAction(newAction)
|
||||
toolbar.addAction(deleteAction)
|
||||
toolbar.addAction(copyAction)
|
||||
@ -457,7 +504,7 @@ def addNewRecord():
|
||||
tblName = i[0]
|
||||
|
||||
#print(tblName)
|
||||
editForm = EditForm(tblName, tblDescr)
|
||||
editForm = EditForm(tblName, tblDescr, 'add')
|
||||
editForm.show()
|
||||
#editForm.setParent(listDBTables)
|
||||
#editForm.show()
|
||||
@ -497,27 +544,58 @@ def showRelationsRecords(fieldIndex, fieldValue):
|
||||
addDataIntoTable(tbl, tblRelationsData, qweryResult)
|
||||
# пишем название активной таблицы БД в строку статуса
|
||||
tblRelationsData.setStatusTip(tbl)
|
||||
|
||||
# Удаление записи
|
||||
def deleteRecord(tableWidget, row, dbTableName, valueList):
|
||||
global dbFieldRelationValueList
|
||||
#print(tableWidget, row, dbTableName, valueList)
|
||||
#print(self.columnCount())
|
||||
i = 0
|
||||
#print(valueList)
|
||||
for val in valueList:
|
||||
#print(tableWidget.item(row, i))
|
||||
#print('Значение из таблицы-->',valueList[i])
|
||||
for item in dbFieldRelationValueList:
|
||||
if item[0] == tableWidget.item(row, i):
|
||||
#print(item[0])
|
||||
#print('еще значение',tableWidget.item(row, i).text(), item[0])
|
||||
value = item[3]
|
||||
valueList.pop(i)
|
||||
valueList.insert(i, item[3])
|
||||
|
||||
i += 1
|
||||
#print(valueList)
|
||||
dm.deleteRecordsFromDB(dbTableName, valueList)
|
||||
# Редактирование записи
|
||||
def editRecord(tableWidget, row, dbTableName, valueList):
|
||||
global dbFieldRelationValueList
|
||||
editForm = EditForm(dbTableName, dm.getTablesDescriptionOfName(dbTableName), 'edit')
|
||||
editForm.show()
|
||||
i = 0
|
||||
for val in valueList:
|
||||
for item in dbFieldRelationValueList:
|
||||
if item[0] == tableWidget.item(row, i):
|
||||
value = item[3]
|
||||
valueList.pop(i)
|
||||
valueList.insert(i, item[3])
|
||||
val = item[3]
|
||||
#print(val)
|
||||
editForm.widgetsList[i][1].setText(val)
|
||||
i += 1
|
||||
#print(valueList)
|
||||
|
||||
#print(editForm.widgetsList)
|
||||
#dm.deleteRecordsFromDB(dbTableName, valueList)
|
||||
|
||||
|
||||
def showStructure():
|
||||
global tabRelationsData, listDBTables
|
||||
tblDescr = listDBTables.model().data(listDBTables.currentIndex())
|
||||
i = 0
|
||||
for i in dbTablesList:
|
||||
if i[1] == tblDescr:
|
||||
tblName = i[0]
|
||||
print(tblName)
|
||||
#print(dm.getTableStructure(tblName))
|
||||
print(dm.getFields(tblName))
|
||||
print(dm.getTableStructureFromDB(tblName))
|
||||
|
||||
def openTemplate():
|
||||
global template_file, template_dir
|
||||
template_file = QFileDialog.getOpenFileName(None, 'Open file', template_dir)[0]
|
||||
dm.initDBstructure(template_file)
|
||||
|
||||
|
||||
def main():
|
||||
global dbTablesList, listDBTables, tabRelationsData, dbFieldRelationValueList
|
||||
@ -555,12 +633,12 @@ def main():
|
||||
print(dm.getTablesNameOfDescription(listDBTables.model().data(listDBTables.currentIndex())))
|
||||
|
||||
|
||||
mainWin.setGeometry(300, 300, 800, 600)
|
||||
mainWin.setGeometry(300, 300, 1024, 800)
|
||||
mainWin.setWindowTitle('Data manipulator')
|
||||
mainWin.show()
|
||||
|
||||
return app.exec_()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
print(template_dir)
|
||||
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
pymysql==1.0.2
|
||||
PyQt5==5.15.7
|
93
test.py
93
test.py
@ -1,93 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
#############################################################################
|
||||
##
|
||||
## Copyright (C) 2013 Riverbank Computing Limited.
|
||||
## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
## All rights reserved.
|
||||
##
|
||||
## This file is part of the examples of PyQt.
|
||||
##
|
||||
## $QT_BEGIN_LICENSE:BSD$
|
||||
## You may use this file under the terms of the BSD license as follows:
|
||||
##
|
||||
## "Redistribution and use in source and binary forms, with or without
|
||||
## modification, are permitted provided that the following conditions are
|
||||
## met:
|
||||
## * Redistributions of source code must retain the above copyright
|
||||
## notice, this list of conditions and the following disclaimer.
|
||||
## * Redistributions in binary form must reproduce the above copyright
|
||||
## notice, this list of conditions and the following disclaimer in
|
||||
## the documentation and/or other materials provided with the
|
||||
## distribution.
|
||||
## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
## the names of its contributors may be used to endorse or promote
|
||||
## products derived from this software without specific prior written
|
||||
## permission.
|
||||
##
|
||||
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
## $QT_END_LICENSE$
|
||||
##
|
||||
#############################################################################
|
||||
|
||||
|
||||
from PyQt5.QtCore import QModelIndex, Qt
|
||||
from PyQt5.QtGui import QStandardItemModel
|
||||
from PyQt5.QtWidgets import QApplication, QItemDelegate, QSpinBox, QTableView
|
||||
|
||||
|
||||
class SpinBoxDelegate(QItemDelegate):
|
||||
def createEditor(self, parent, option, index):
|
||||
editor = QSpinBox(parent)
|
||||
editor.setMinimum(0)
|
||||
editor.setMaximum(100)
|
||||
|
||||
return editor
|
||||
|
||||
def setEditorData(self, spinBox, index):
|
||||
value = index.model().data(index, Qt.EditRole)
|
||||
|
||||
spinBox.setValue(value)
|
||||
|
||||
def setModelData(self, spinBox, model, index):
|
||||
spinBox.interpretText()
|
||||
value = spinBox.value()
|
||||
|
||||
model.setData(index, value, Qt.EditRole)
|
||||
|
||||
def updateEditorGeometry(self, editor, option, index):
|
||||
editor.setGeometry(option.rect)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
import sys
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
model = QStandardItemModel(4, 4)
|
||||
tableView = QTableView()
|
||||
tableView.setModel(model)
|
||||
|
||||
delegate = SpinBoxDelegate()
|
||||
tableView.setItemDelegate(delegate)
|
||||
|
||||
for row in range(4):
|
||||
for column in range(4):
|
||||
index = model.index(row, column, QModelIndex())
|
||||
model.setData(index, (row + 1) * (column + 1))
|
||||
|
||||
tableView.setWindowTitle("Spin Box Delegate")
|
||||
tableView.show()
|
||||
sys.exit(app.exec_())
|
Loading…
x
Reference in New Issue
Block a user