c++, java는 보통 단일값 리턴이지만
파이썬은 두 개의 값을 리턴하는게 가능하다. 두 개의 값을 동시에 리턴하기 위해 튜플을 구성하여 리턴한다.
def cal_upper_lower(price):
offset = price * 0.3
upper = price + offset
lower = price - offset
return (upper, lower)
>>> (upper, lower) = cal_upper_lower(10000)
>>> upper
13000.0
>>> lower
7000.0
>>>
파이썬
2015년 11월 2일 월요일
파이썬 문자열 리스트를 단일 문자열로 쉽게 변경하기
문자열 리스트는 필요한 문자열 만큼 쉽게 추가할 수 있는 장점이 있다. 그러나 문자열 리스트를 단일 문자열로 변경할 필요가 종종 있다. 이 때 쉽게 할 수 있는 방법은
''.join(문자열 리스트) 이다.
stringList = []
stringList.append("사과")
stringList.append("배")
stringList.append("귤")
print(''.join(stringList))
''.join(문자열 리스트) 이다.
stringList = []
stringList.append("사과")
stringList.append("배")
stringList.append("귤")
print(''.join(stringList))
PySide API 링크
파이썬으로 GUI 프로그램을 지원하는 여러가지 솔루션이 있지만, Qt계열의 PySide가 문서화가 잘 돼있고 GUI 위젯을 코딩없이 마우스 클릭만으로 구성할 수 있는 Qt 디자이너가 지원되기에 추천한다.
PySide 1.2.1 문서 링크는 http://pyside.github.io/docs/pyside/index.html 이다
PySide 1.2.1 문서 링크는 http://pyside.github.io/docs/pyside/index.html 이다
2015년 10월 15일 목요일
PySide에서 QDataWidgetMapper,QComboBox 매핑하기
PySide에서 MVVM 패턴으로 GUI를 작성하려면 뷰와 뷰모델간의 상호 데이터 전파가 자동으로 전달되어서 서로 일치하도록 하는게 일이다
OOOview와 OOOmodel의 개념으로 지원되는 위젯들은 데이터 전파가 잘되나, 일반 위젯은 뷰-모델의 개념이 없기 때문에 유사한 흉내를 내주기 위해서는 모델을 하나 만들고QDataWidgetMapper로 각각의 위젯과 연결을 해줌으로써 MVVM 패턴을 적용할 수 있을것으로 생각된다.
LineEdit, DateTime, TextEdit 은 매핑한 후 뷰와 모델간 데이터 변경 전달이 자동으로 잘되지만,
ComboBox의 경우 QDataWidgetMapper에서 currentIndex property로 매핑한 경우 상호간 변경내용 전파가 잘되나, currentText로 매핑할 경우 뷰->모델로는 전파가 되나, 모델->뷰로는 전파가 잘 되지 않는다.
이 문제를 해결하기위해 QComboBox를 상속하여 MyComboBox를 만들었다
테스트 화면을 보면 뷰-뷰모델간 동기화를 위한 별도의 코드없이 매핑만으로 같은 모델을 공유하는 두개의 윈도우간 데이터의 변경결과가 자동 반영되는 것을 알 수 있다.
#-*- coding: utf-8 -*-
from PySide.QtGui import QComboBox
from PySide.QtCore import Property, Qt
class MyComboBox(QComboBox):
def __init__(self, params=None):
super().__init__(params)
def set(self, text):
''' 텍스트 값을 설정하면 현재 인덱스 값을 텍스트와 일치하는 인덱스로 변경
'''
self.setCurrentIndex(self.findText(text, Qt.MatchExactly))
def get(self):
return self.currentText()
''' get을 읽기, set을 쓰기 property로 등록
'''
text = Property(str, get, set)
테스트를 위해 회원 등록하는 간단한 GUI의 뷰와 뷰모델은 다음과 같다
import sys
from PySide.QtGui import QWidget, QApplication, QDataWidgetMapper
from Ui_member import Ui_member
from src.mvvmTest.MemberVm import MemberVm
class MemberV(QWidget):
'''
classdocs
'''
def __init__(self, params=None):
'''
Constructor
'''
super().__init__()
self.ui = Ui_member()
self.ui.setupUi(self)
self.initCombo()
self.vm = params
self.bind()
self.show()
def initCombo(self):
self.ui.comboBoxDept.addItems("월화수목금토일")
self.ui.comboBoxUsage.addItems("ox")
def bind(self):
self.mapper = QDataWidgetMapper()
self.mapper.setModel(self.vm.model)
self.mapper.addMapping(self.ui.lineEditId, 0)
self.mapper.addMapping(self.ui.lineEditName, 1)
self.mapper.addMapping(self.ui.lineEditPwd, 2)
self.mapper.addMapping(self.ui.lineEditPwd2, 3)
self.mapper.addMapping(self.ui.comboBoxDept, 4, "text")
self.mapper.addMapping(self.ui.comboBoxUsage, 5)
self.mapper.addMapping(self.ui.dateEdit, 6)
self.mapper.addMapping(self.ui.plainTextEdit, 7)
self.mapper.toFirst()
if __name__ == '__main__':
app = QApplication(sys.argv)
vm = MemberVm()
widget = MemberV(vm)
widget2 = MemberV(vm)
widget.show()
widget2.show()
app.exec_()
pass
from PySide.QtGui import QStandardItemModel, QStandardItem
class MemberVm(object):
'''
classdocs
'''
def __init__(self, params=None):
'''
Constructor
'''
self.model = QStandardItemModel()
_id = QStandardItem("")
name = QStandardItem("")
pwd = QStandardItem("")
pwd2 = QStandardItem("")
dept = QStandardItem("수")
usage = QStandardItem("o")
date = QStandardItem("2010-01-01")
etc = QStandardItem("비고")
self.model.setItem(0, 0, _id)
self.model.setItem(0, 1, name)
self.model.setItem(0, 2, pwd)
self.model.setItem(0, 3, pwd2)
self.model.setItem(0, 4, dept)
self.model.setItem(0, 5, usage)
self.model.setItem(0, 6, date)
self.model.setItem(0, 7, etc)
self.model.itemChanged.connect(self.printModel)
def printModel(self):
for col in range(7):
print(self.model.item(0,col).text())
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Ui_member.ui'
#
# Created: Wed Oct 14 00:34:37 2015
# by: pyside-uic 0.2.15 running on PySide 1.2.2
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
from PySide.QtGui import QComboBox
from MyComboBox import MyComboBox
class Ui_member(object):
def setupUi(self, member):
member.setObjectName("member")
member.resize(212, 290)
self.gridLayout = QtGui.QGridLayout(member)
self.gridLayout.setObjectName("gridLayout")
self.label = QtGui.QLabel(member)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.lineEditId = QtGui.QLineEdit(member)
self.lineEditId.setObjectName("lineEditId")
self.gridLayout.addWidget(self.lineEditId, 0, 1, 1, 1)
self.label_2 = QtGui.QLabel(member)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.lineEditName = QtGui.QLineEdit(member)
self.lineEditName.setObjectName("lineEditName")
self.gridLayout.addWidget(self.lineEditName, 1, 1, 1, 1)
self.label_3 = QtGui.QLabel(member)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.lineEditPwd = QtGui.QLineEdit(member)
self.lineEditPwd.setObjectName("lineEditPwd")
self.gridLayout.addWidget(self.lineEditPwd, 2, 1, 1, 1)
self.label_4 = QtGui.QLabel(member)
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 1)
self.lineEditPwd2 = QtGui.QLineEdit(member)
self.lineEditPwd2.setObjectName("lineEditPwd2")
self.gridLayout.addWidget(self.lineEditPwd2, 3, 1, 1, 1)
self.label_5 = QtGui.QLabel(member)
self.label_5.setObjectName("label_5")
self.gridLayout.addWidget(self.label_5, 4, 0, 1, 1)
# self.comboBoxDept = QtGui.QComboBox(member)
self.comboBoxDept = MyComboBox(member)
self.comboBoxDept.setObjectName("comboBoxDept")
self.gridLayout.addWidget(self.comboBoxDept, 4, 1, 1, 1)
self.label_6 = QtGui.QLabel(member)
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.comboBoxUsage = QtGui.QComboBox(member)
self.comboBoxUsage.setObjectName("comboBoxUsage")
self.gridLayout.addWidget(self.comboBoxUsage, 5, 1, 1, 1)
self.label_7 = QtGui.QLabel(member)
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 6, 0, 1, 1)
self.dateEdit = QtGui.QDateEdit(member)
self.dateEdit.setObjectName("dateEdit")
self.gridLayout.addWidget(self.dateEdit, 6, 1, 1, 1)
self.label_8 = QtGui.QLabel(member)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 7, 0, 1, 1)
self.plainTextEdit = QtGui.QPlainTextEdit(member)
self.plainTextEdit.setObjectName("plainTextEdit")
self.gridLayout.addWidget(self.plainTextEdit, 7, 1, 1, 1)
self.retranslateUi(member)
QtCore.QMetaObject.connectSlotsByName(member)
def retranslateUi(self, member):
member.setWindowTitle(QtGui.QApplication.translate("member", "사용자", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("member", "아이디:", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("member", "이름:", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("member", "비번:", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("member", "비번확인:", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("member", "부서:", None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("member", "사용상태:", None, QtGui.QApplication.UnicodeUTF8))
self.label_7.setText(QtGui.QApplication.translate("member", "변경일:", None, QtGui.QApplication.UnicodeUTF8))
self.label_8.setText(QtGui.QApplication.translate("member", "비고:", None, QtGui.QApplication.UnicodeUTF8))
OOOview와 OOOmodel의 개념으로 지원되는 위젯들은 데이터 전파가 잘되나, 일반 위젯은 뷰-모델의 개념이 없기 때문에 유사한 흉내를 내주기 위해서는 모델을 하나 만들고QDataWidgetMapper로 각각의 위젯과 연결을 해줌으로써 MVVM 패턴을 적용할 수 있을것으로 생각된다.
LineEdit, DateTime, TextEdit 은 매핑한 후 뷰와 모델간 데이터 변경 전달이 자동으로 잘되지만,
ComboBox의 경우 QDataWidgetMapper에서 currentIndex property로 매핑한 경우 상호간 변경내용 전파가 잘되나, currentText로 매핑할 경우 뷰->모델로는 전파가 되나, 모델->뷰로는 전파가 잘 되지 않는다.
이 문제를 해결하기위해 QComboBox를 상속하여 MyComboBox를 만들었다
테스트 화면을 보면 뷰-뷰모델간 동기화를 위한 별도의 코드없이 매핑만으로 같은 모델을 공유하는 두개의 윈도우간 데이터의 변경결과가 자동 반영되는 것을 알 수 있다.
- MyComboBox.py
#-*- coding: utf-8 -*-
from PySide.QtGui import QComboBox
from PySide.QtCore import Property, Qt
class MyComboBox(QComboBox):
def __init__(self, params=None):
super().__init__(params)
def set(self, text):
''' 텍스트 값을 설정하면 현재 인덱스 값을 텍스트와 일치하는 인덱스로 변경
'''
self.setCurrentIndex(self.findText(text, Qt.MatchExactly))
def get(self):
return self.currentText()
''' get을 읽기, set을 쓰기 property로 등록
'''
text = Property(str, get, set)
테스트를 위해 회원 등록하는 간단한 GUI의 뷰와 뷰모델은 다음과 같다
- MemberV.py
import sys
from PySide.QtGui import QWidget, QApplication, QDataWidgetMapper
from Ui_member import Ui_member
from src.mvvmTest.MemberVm import MemberVm
class MemberV(QWidget):
'''
classdocs
'''
def __init__(self, params=None):
'''
Constructor
'''
super().__init__()
self.ui = Ui_member()
self.ui.setupUi(self)
self.initCombo()
self.vm = params
self.bind()
self.show()
def initCombo(self):
self.ui.comboBoxDept.addItems("월화수목금토일")
self.ui.comboBoxUsage.addItems("ox")
def bind(self):
self.mapper = QDataWidgetMapper()
self.mapper.setModel(self.vm.model)
self.mapper.addMapping(self.ui.lineEditId, 0)
self.mapper.addMapping(self.ui.lineEditName, 1)
self.mapper.addMapping(self.ui.lineEditPwd, 2)
self.mapper.addMapping(self.ui.lineEditPwd2, 3)
self.mapper.addMapping(self.ui.comboBoxDept, 4, "text")
self.mapper.addMapping(self.ui.comboBoxUsage, 5)
self.mapper.addMapping(self.ui.dateEdit, 6)
self.mapper.addMapping(self.ui.plainTextEdit, 7)
self.mapper.toFirst()
if __name__ == '__main__':
app = QApplication(sys.argv)
vm = MemberVm()
widget = MemberV(vm)
widget2 = MemberV(vm)
widget.show()
widget2.show()
app.exec_()
pass
- MemberVm.py
from PySide.QtGui import QStandardItemModel, QStandardItem
class MemberVm(object):
'''
classdocs
'''
def __init__(self, params=None):
'''
Constructor
'''
self.model = QStandardItemModel()
_id = QStandardItem("")
name = QStandardItem("")
pwd = QStandardItem("")
pwd2 = QStandardItem("")
dept = QStandardItem("수")
usage = QStandardItem("o")
date = QStandardItem("2010-01-01")
etc = QStandardItem("비고")
self.model.setItem(0, 0, _id)
self.model.setItem(0, 1, name)
self.model.setItem(0, 2, pwd)
self.model.setItem(0, 3, pwd2)
self.model.setItem(0, 4, dept)
self.model.setItem(0, 5, usage)
self.model.setItem(0, 6, date)
self.model.setItem(0, 7, etc)
self.model.itemChanged.connect(self.printModel)
def printModel(self):
for col in range(7):
print(self.model.item(0,col).text())
- Ui_member.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Ui_member.ui'
#
# Created: Wed Oct 14 00:34:37 2015
# by: pyside-uic 0.2.15 running on PySide 1.2.2
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
from PySide.QtGui import QComboBox
from MyComboBox import MyComboBox
class Ui_member(object):
def setupUi(self, member):
member.setObjectName("member")
member.resize(212, 290)
self.gridLayout = QtGui.QGridLayout(member)
self.gridLayout.setObjectName("gridLayout")
self.label = QtGui.QLabel(member)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.lineEditId = QtGui.QLineEdit(member)
self.lineEditId.setObjectName("lineEditId")
self.gridLayout.addWidget(self.lineEditId, 0, 1, 1, 1)
self.label_2 = QtGui.QLabel(member)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.lineEditName = QtGui.QLineEdit(member)
self.lineEditName.setObjectName("lineEditName")
self.gridLayout.addWidget(self.lineEditName, 1, 1, 1, 1)
self.label_3 = QtGui.QLabel(member)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
self.lineEditPwd = QtGui.QLineEdit(member)
self.lineEditPwd.setObjectName("lineEditPwd")
self.gridLayout.addWidget(self.lineEditPwd, 2, 1, 1, 1)
self.label_4 = QtGui.QLabel(member)
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 1)
self.lineEditPwd2 = QtGui.QLineEdit(member)
self.lineEditPwd2.setObjectName("lineEditPwd2")
self.gridLayout.addWidget(self.lineEditPwd2, 3, 1, 1, 1)
self.label_5 = QtGui.QLabel(member)
self.label_5.setObjectName("label_5")
self.gridLayout.addWidget(self.label_5, 4, 0, 1, 1)
# self.comboBoxDept = QtGui.QComboBox(member)
self.comboBoxDept = MyComboBox(member)
self.comboBoxDept.setObjectName("comboBoxDept")
self.gridLayout.addWidget(self.comboBoxDept, 4, 1, 1, 1)
self.label_6 = QtGui.QLabel(member)
self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.comboBoxUsage = QtGui.QComboBox(member)
self.comboBoxUsage.setObjectName("comboBoxUsage")
self.gridLayout.addWidget(self.comboBoxUsage, 5, 1, 1, 1)
self.label_7 = QtGui.QLabel(member)
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 6, 0, 1, 1)
self.dateEdit = QtGui.QDateEdit(member)
self.dateEdit.setObjectName("dateEdit")
self.gridLayout.addWidget(self.dateEdit, 6, 1, 1, 1)
self.label_8 = QtGui.QLabel(member)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 7, 0, 1, 1)
self.plainTextEdit = QtGui.QPlainTextEdit(member)
self.plainTextEdit.setObjectName("plainTextEdit")
self.gridLayout.addWidget(self.plainTextEdit, 7, 1, 1, 1)
self.retranslateUi(member)
QtCore.QMetaObject.connectSlotsByName(member)
def retranslateUi(self, member):
member.setWindowTitle(QtGui.QApplication.translate("member", "사용자", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("member", "아이디:", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("member", "이름:", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("member", "비번:", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("member", "비번확인:", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("member", "부서:", None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("member", "사용상태:", None, QtGui.QApplication.UnicodeUTF8))
self.label_7.setText(QtGui.QApplication.translate("member", "변경일:", None, QtGui.QApplication.UnicodeUTF8))
self.label_8.setText(QtGui.QApplication.translate("member", "비고:", None, QtGui.QApplication.UnicodeUTF8))
2015년 10월 13일 화요일
PySide QTableView와 QTableModel에서 뷰에서 한 건만 변경해도 여러건이 같이 변경되는 문제
여러가지 테스트를 한 결과,
Postgresql 테이블에 primary key가 없으면 각 행을 구분할 방법이 없기 때문에 데이터 값이 동일한 건은 한건만 수정해도 값이 같은 다른 건들도 같이 업데이트 되는 문제임을 알았다.
알고나니 우습지만, 이 문제 때문에 PySide나 Postgresql의 버그를 의심도 했을만큼 심각하게 고민했었다.
결국 QTableModel이 참조하는 테이블에 유니크 키를 만들어서 문제를 해결했다.
Postgresql 테이블에 primary key가 없으면 각 행을 구분할 방법이 없기 때문에 데이터 값이 동일한 건은 한건만 수정해도 값이 같은 다른 건들도 같이 업데이트 되는 문제임을 알았다.
알고나니 우습지만, 이 문제 때문에 PySide나 Postgresql의 버그를 의심도 했을만큼 심각하게 고민했었다.
결국 QTableModel이 참조하는 테이블에 유니크 키를 만들어서 문제를 해결했다.
피드 구독하기:
덧글 (Atom)
