오늘 할 일
- 폴더 내에 있는 파일을 임의로 열고 HTML 내에 테이블을 PyQt5로 출력
- 테이블의 셀 중 하나를 선택하여 답으로 지정
- PyQt 내에 선택한 셀이 답이 되는 질문을 작성하는 박스 생성
- 확인 버튼을 누르면 지정된 엑셀로 내용 전송
진행순서
1. PyQt5로 창 만들기
2. 폴더 내 임의의 파일 열기
3. html 내 테이블 파싱
4. UI 내에 테이블 띄우기
5. 테이블의 내용을 답으로 선택
6. 작성한 내용 엑셀로 보내기
7. 코드 리팩토링 및 주석 작성
1. PyQt5로 창 만들기
제작 해야 하는 거
- 랜덤 버튼, 질문 창 확인 버튼
import sys
from PyQt5.QtWidgets import *
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('DataSet Tool')
self.center()
self.setDisplay()
self.show()
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def setDisplay(self):
grid = QGridLayout()
self.setLayout(grid)
grid.addWidget(QLabel('Question:'), 1, 0)
#위젯 만들기
randomBtn = QPushButton('Show Table',self)
quesConent = QLineEdit()
confirmBtn = QPushButton('Confirm',self)
#위젯 크기 설정
randomBtn.setFixedSize(100, 30)
confirmBtn.setFixedSize(100,30)
quesConent.setFixedSize(500,25)
#그리드에 위젯 추가
grid.addWidget(randomBtn, 0, 0)
grid.addWidget(confirmBtn, 0, 1)
grid.addWidget(quesConent, 1, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyApp()
sys.exit(app.exec_())
2. 폴더 내 임의의 파일 열기
버튼에 시그널 함수 연결
버튼을 클릭할 때 함수가 동작하도록 한다.
randomBtn.clicked.connect(self.randomBtnFunc)
confirmBtn.clicked.connect(self.confirmBtnFunc)
def randomBtnFunc(self):
print("random!!!")
def confirmBtnFunc(self):
print("confirm!!!")
일단 해당 폴더의 파일 개수를 구해서 범위로 잡고 범위 내 임의의 수를 random을 통해 구했다.
파일 경로 내용을 read() 를 통해 다 읽어온다.
def randomBtnFunc(self):
filePath = 'C:/Users/ch_pa/PycharmProjects/HtmlTableParsingTool/html/'
fileList = os.listdir(filePath) #파일 경로
num = random.randrange(0, len(fileList) - 1)
filePath = filePath + fileList[num]
f = open(filePath,'r', encoding='UTF8')
htmlDocs = f.read()
print(htmlDocs)
3. html 내 테이블 파싱 & 4. UI 내에 테이블 띄우기
어떻게 html 내 table을 창에 출력할 수 있을까 고민하고 html 자체 위젯을 pyqt 창 내에 출력할 수 있는 방식을 알아봤으나 찾지 못했다. (QtWebEngineWidgets 같은 경우에는 인터넷 페이지를 들고 오는 거라 html 파일을 들고 오는 내 경우엔 맞지 않았다.)
그래서 html 코드를 뽑아오고 table 코드를 html_parser로 뽑아와서 for문을 사용해 tableWidget안에 내용을 만들어준 후 grid에 추가했다.
나중에 셀을 선택할 때도 도움이 될거라 여겨서 tableWidget을 선택했다.
고생했던 건 layout에 테이블을 추가시킬 때 slot에 인자를 넘기는 법을 몰랐다는 것이다.
grid가 넘어가지 않으니 함수가 실행되도 테이블을 추가시킬 창을 발견하지 못해서 프로그램이 종료되었다.
grid를 넘겨주는 방법은 참고 블로그를 확인하면 된다.
randomBtn.clicked.connect(lambda:self.randomBtnFunc(grid))
#slot에 인자 넘기기
randomBtn.clicked.connect(lambda:self.randomBtnFunc(grid))
#randomBtn이 눌리면 작동하는 함수
def randomBtnFunc(self,grid):
#파일 읽기
filePath = 'C:/Users/ch_pa/PycharmProjects/HtmlTableParsingTool/html/'
fileList = os.listdir(filePath) #파일 경로
num = random.randrange(0, len(fileList) - 1)
filePath = filePath + fileList[num]
print(filePath)
f = open(filePath,'r', encoding='UTF8')
htmlDocs = f.read()
#print(htmlDocs)
#테이블 코드 추출
soup = BeautifulSoup(htmlDocs,'html.parser')
temp = soup.find_all('table')
print(len(temp))
tableNum = random.randrange(0,len(temp)-1)
#테이블 리스트로 출력
p = parser.make2d(temp[tableNum])
print(p)
colLen = len(p[0])
rowLen = len(p)
#tableWidget 생성
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(rowLen)
self.tableWidget.setColumnCount(colLen)
#tableWidget 안에 테이블 내용 삽입 후 위젯 추가
for i in range(rowLen):
for j in range(colLen):
self.tableWidget.setItem(i, j, QTableWidgetItem(p[i][j]))
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
grid.addWidget(self.tableWidget,2,1)
self.resize(1000, 1000)
5. 테이블의 내용을 답으로 선택
def setCellValue(self,row,column):
item = self.tableWidget.item(row, column)
value = item.text()
label_string = 'Row: ' + str(row + 1) + ', Column: ' + str(column + 1) + ', Value: ' + str(value)
self.label.setText(label_string)
6. 작성 내용 엑셀로 보내기
def confirmBtnFunc(self):
text = self.quesContent.text()
reply = QMessageBox.question(self, 'Confirm', '작성한 내용은 다음과 같습니다.\n질문 : ' + self.quesContent.text() + '\n답 : ' + self.answer.text() ,QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
print(reply)
if reply == QMessageBox.Yes:
wb = openpyxl.load_workbook('test.xlsx')
ws = wb.active
print([self.fileName.text(),self.quesContent.text(),self.answer.text()])
ws.append([self.fileName.text(),self.quesContent.text(),self.answer.text()])
wb.save('test.xlsx')
self.quesContent.clear()
else:
print(text)
#
7. 코드 리팩토링 및 주석 작성
함수를 분리하고 주석을 작성했다.
import os
import random
import sys
import openpyxl
from bs4 import BeautifulSoup
from html_table_parser import parser_functions as parser
from PyQt5.QtWidgets import *
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
#UI초기화 함수
def initUI(self):
self.setDisplay() #창 설정
self.clickedConnFunc() #시그널 함수 위젯과 연결
self.center() #창을 가운데에서 생성
self.show() #창 실행
#창을 설정하는 함수
def setDisplay(self):
self.setWindowTitle('DataSet Tool') #창의 제목
self.grid = QGridLayout() #그리드 레이아웃
self.setLayout(self.grid)
self.makeWidget() #위젯 생성
self.setWidgetSize() #위젯 크기 설정
self.addWidgetInGrid() #위젯을 그리드에 추가
# 위젯을 생성하는 함수
def makeWidget(self):
self.randomBtn = QPushButton('Show Table', self) #임의의 파일에서 임의의 테이블을 추출하는 버튼
self.confirmBtn = QPushButton('Confirm', self) #질문을 생성한 후 엑셀에 추가하는 버튼
self.quesContent = QLineEdit() #질문이 들어가는 라인 에디타
self.tableWidget = QTableWidget() #테이블을 표시할 위젯
self.label = QLabel('')
self.answer = QLabel('')
self.fileName = QLabel('')
# 위젯 크기 설정하는 함수
def setWidgetSize(self):
self.randomBtn.setFixedSize(100, 30)
self.confirmBtn.setFixedSize(100, 30)
self.quesContent.setFixedSize(800, 25)
# 그리드에 위젯 추가하는 함수
def addWidgetInGrid(self):
self.grid.addWidget(QLabel('Question:'), 1, 0)
self.grid.addWidget(self.randomBtn, 0, 0)
self.grid.addWidget(self.confirmBtn, 0, 1)
self.grid.addWidget(self.quesContent, 1, 1)
self.grid.addWidget(self.label, 3, 1)
#시그널 함수를 연결하는 함수
def clickedConnFunc(self):
self.randomBtn.clicked.connect(self.randomBtnFunc)
self.confirmBtn.clicked.connect(self.confirmBtnFunc)
self.tableWidget.cellClicked.connect(self.setCellValue)
#randomBtn이 눌리면 작동하는 함수
def randomBtnFunc(self):
self.readFile() #임의의 파일을 읽어오는 함수
self.getTableOrder() #임의의 테이블 코드를 추출하는 함수
self.setTableInWindow() #테이블을 창에 표시하는 함수
self.resize(1000, 1000)
# 임의의 파일을 읽어오는 함수
def readFile(self):
# 데이터가 있는 폴더 설정
#------------------------------------------------------------------------------------
filePath = 'C:/Users/ch_pa/PycharmProjects/HtmlTableParsingTool/html/'
#------------------------------------------------------------------------------------
fileList = os.listdir(filePath) # 파일 경로
num = random.randrange(0, len(fileList) - 1) #폴더 내 임의의 파일 선택
self.fileName.setText(fileList[num])
filePath = filePath + fileList[num]
f = open(filePath, 'r', encoding='UTF8')
self.htmlDocs = f.read()
# 임의의 테이블 코드를 추출하는 함수
def getTableOrder(self):
#html parser을 활용하여 파일 내에 테이블 코드를 추출함
soup = BeautifulSoup(self.htmlDocs, 'html.parser')
temp = soup.find_all('table')
self.tableNum = random.randrange(0, len(temp) - 1) #테이블의 수를 활용하여 임의의 테이블을 선택
self.table = parser.make2d(temp[self.tableNum]) #테이블 위젯에서 테이블 값을 한 줄 씩 저장
self.colLen = len(self.table[0]) #테이블의 열 갯수 추출
self.rowLen = len(self.table) #테이블의 행 갯수 추출
#테이블 위젯에서 열과 행 설정
self.tableWidget.setRowCount(self.rowLen)
self.tableWidget.setColumnCount(self.colLen)
# 테이블을 창에 표시하는 함수
def setTableInWindow(self):
#테이블의 열과 행의 갯수에 따라 테이블 위젯의 내용 입력
for i in range(self.rowLen):
for j in range(self.colLen):
self.tableWidget.setItem(i, j, QTableWidgetItem(self.table[i][j]))
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) #테이블의 열 너비에 맞춤
self.grid.addWidget(self.tableWidget, 2, 1)
# 테이블에서 선택한 셀의 값을 answer 안에 설정하고 표시
def setCellValue(self,row,column):
item = self.tableWidget.item(row, column)
value = item.text()
label_string = 'Row: ' + str(row + 1) + ', Column: ' + str(column + 1) + ', Value: ' + str(value)
self.answer.setText(str(value))
self.label.setText(label_string)
# 질문 내용과 답을 확인하고 엑셀로 입력하는 함수
def confirmBtnFunc(self):
text = self.quesContent.text() #질문 내용 추출
#메세지활용을 통해 질문과 답 확인 표시 후 응답 변수 값 설정
reply = QMessageBox.question(self, 'Confirm', '작성한 내용은 다음과 같습니다.\n질문 : ' + self.quesContent.text() + '\n답 : ' + self.answer.text() ,QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
#응답에 따른 조건문 실행
if reply == QMessageBox.Yes:
wb = openpyxl.load_workbook('test.xlsx') #test.xlsx이라는 엑셀 파일을 로드
ws = wb.active
ws.append([self.fileName.text(),self.quesContent.text(),self.answer.text()]) #[파일 명, 질문 내용, 답] 행추가
wb.save('test.xlsx') #엑셀 파일 저장
self.quesContent.clear() #질문 내용 초기화
else:
print(text)
#팡이 생성될 때 가운데로 오게 하는 함수
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyApp()
sys.exit(app.exec_())
프로그램 실행 화면
다음에 추가할 내용
- 확장자 html 만 데이터로 사용 -> 현재 pdf, hwp 확장자면
- 데이터 경로 설정 창
- 테이블 표시 시 원본 html 화면 볼 수 있게 버튼 만들기
- 연구실에 추가적으로 어떤 내용 삽입해야 하는지 물어보기
참고 블로그
https://blog.naver.com/PostView.nhn?blogId=21ahn&logNo=221388594129
https://codetorial.net/articles/qtablewidget_pyqt5_2.html
https://needjarvis.tistory.com/640
'공부 > 졸업과제' 카테고리의 다른 글
데이터 툴 개선(엑셀 삽입 및 파일 열기 버튼 생성) (0) | 2022.03.18 |
---|