#coding=utf-8 import os,sys,re,time import pygame import random from win32api import GetSystemMetrics from tkinter import messagebox pygame.init() pygame.display.set_caption("我的控制元件") percent = 0.6 screen_width = GetSystemMetrics(0) screen_height = GetSystemMetrics(1) window_width = int(screen_width*percent) window_height = int(screen_height*percent) dt = 0 clock = pygame.time.Clock() screen = pygame.display.set_mode((window_width, window_height)) #停止處理輸入法事件 pygame.key.stop_text_input() def showMsg(msg): messagebox.showinfo('提示資訊', msg) class Button: def __init__(self, x, y, w, h): self.x = x self.y = y self.w = w self.h = h self.color = 'gray' self.text = '按鈕' self.text_color = 'black' self.text_size = 12 self.border_width = 1 self.border_color = 'black' self.font_path = os.path.join(os.path.dirname(sys.argv[0]), 'simsun.ttc') self.my_font = pygame.font.Font(self.font_path, self.text_size) def setColor(self, color): self.color = color def setText(self, text): self.text = text def getText(self): return self.text def setTextColor(self, text_color): self.text_color = text_color def setTextSize(self, text_size): self.text_size = text_size self.my_font = pygame.font.Font(self.font_path, self.text_size) def setBorderWidth(self, border_width): self.border_width = border_width def setBorderColor(self, border_color): self.border_color = border_color def draw(self, win): pygame.draw.rect(win, self.color, (self.x, self.y, self.w, self.h)) if self.border_width > 0: pygame.draw.rect(win, self.border_color, (self.x, self.y, self.w, self.h), self.border_width) text = self.my_font.render(self.text, True, self.text_color) myx = self.x + (self.w - text.get_width()) / 2 myy = self.y + (self.h - text.get_height()) / 2 win.blit(text, (myx, myy)) def click(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if self.x + self.w > event.pos[0] > self.x and self.y + self.h > event.pos[1] > self.y: return True return False class Label: def __init__(self, x, y, w, h): self.x = x self.y = y self.w = w self.h = h self.color = 'white' self.text = '' self.text_color = 'black' self.text_size = 12 self.border_width = 0 self.border_color = '' self.font_path = os.path.join(os.path.dirname(sys.argv[0]), 'simsun.ttc') self.my_font = pygame.font.Font(self.font_path, self.text_size) def setColor(self, color): self.color = color def setText(self, text): self.text = text def getText(self): return self.text def setTextColor(self, text_color): self.text_color = text_color def setTextSize(self, text_size): self.text_size = text_size self.my_font = pygame.font.Font(self.font_path, self.text_size) def setBorderWidth(self, border_width): self.border_width = border_width def setBorderColor(self, border_color): self.border_color = border_color def getCharWH(self): padding_percent_width = 0.3 padding_percent_height = 0.3 test_text1 = '測試字串' test_text2 = self.my_font.render(test_text1, True, self.text_color) char_width = test_text2.get_width() / len(test_text1) char_height = test_text2.get_height() padding_width = char_width * padding_percent_width padding_height = char_height * padding_percent_height max_field_num = int((self.w - padding_width * 2) / char_width) return (char_height, padding_width, padding_height, max_field_num) def getTrueLines(self, max_field_num): texts = self.text.split("\n") k = 0 for i,mytext in enumerate(texts): while len(mytext) > max_field_num: submytext = mytext[0:max_field_num] mytext = mytext[max_field_num:] k += 1 k += 1 return k+1 def draw(self, win): (char_height, padding_width, padding_height, max_field_num) = self.getCharWH() lineNum = self.getTrueLines(max_field_num) if lineNum * char_height > self.h: self.h = lineNum * char_height pygame.draw.rect(win, self.color, (self.x, self.y, self.w, self.h)) if self.border_width > 0: pygame.draw.rect(win, self.border_color, (self.x, self.y, self.w, self.h), self.border_width) texts = self.text.split("\n") k = 0 for i,mytext in enumerate(texts): while len(mytext) > max_field_num: submytext = mytext[0:max_field_num] subtext = self.my_font.render(submytext, True, self.text_color) submyx = self.x + padding_width submyy = self.y + padding_height + char_height * k win.blit(subtext, (submyx, submyy)) mytext = mytext[max_field_num:] k += 1 text = self.my_font.render(mytext, True, self.text_color) myx = self.x + padding_width myy = self.y + padding_height + char_height * k win.blit(text, (myx, myy)) k += 1 class TextArea: startx = 0 endx = 0 starty = 0 endy = 0 padding_width = 0 padding_height = 0 char_width = 0 char_height = 0 max_field_num = 0 collbar_color = 'gray' collbar_bgcolor = 'lightgray' collbar_width_x = 0 collbar_height_x = 5 collbar_offset_x = 0 collbar_percent_x = 0 dragging_x = False collbar_width_y = 5 collbar_height_y = 0 collbar_offset_y = 0 collbar_percent_y = 0 dragging_y = False line_wrap = False def __init__(self, x, y, w, h, text, text_size = 12): self.x = x self.y = y self.w = w self.h = h self.color = 'white' self.text = text self.text_color = 'black' self.text_size = text_size self.border_width = 0 self.border_color = '' self.font_path = os.path.join(os.path.dirname(sys.argv[0]), 'simsun.ttc') self.my_font = pygame.font.Font(self.font_path, self.text_size) self.getCharWH() def setColor(self, color): self.color = color def setText(self, text): self.text = text self.getCharWH() def getText(self): return self.text def setTextColor(self, text_color): self.text_color = text_color def setTextSize(self, text_size): self.text_size = text_size self.my_font = pygame.font.Font(self.font_path, self.text_size) self.getCharWH() def setBorderWidth(self, border_width): self.border_width = border_width def setBorderColor(self, border_color): self.border_color = border_color def getCharWH(self): padding_percent_width = 0.3 padding_percent_height = 0.3 test_text1 = '測試字串' test_text2 = self.my_font.render(test_text1, True, self.text_color) self.char_width = test_text2.get_width() / len(test_text1) self.char_height = test_text2.get_height() self.padding_width = self.char_width * padding_percent_width self.padding_height = self.char_height * padding_percent_height self.max_field_num = self.getMaxFieldNum() showLineNum = self.getShowLineNum() totalLineNum = self.getTotalLineNum() print(showLineNum) print(totalLineNum) print() self.collbar_percent_y = showLineNum / totalLineNum if totalLineNum * self.char_height + 2 * self.padding_height+self.collbar_height_x > self.h: self.collbar_height_y = self.collbar_percent_y * (self.h - self.padding_height * 2-self.collbar_height_x) showFieldNum = self.getShowFieldNum() totalFieldNum = self.getTotalFieldNum() self.collbar_percent_x = showFieldNum / totalFieldNum if totalFieldNum * self.char_width + 2 * self.padding_width+self.collbar_width_y > self.w: self.collbar_width_x = self.collbar_percent_x * (self.w - self.padding_width * 2-self.collbar_width_y) #計算每行多少個字 def getMaxFieldNum(self): num = 0 if self.line_wrap == True: #折行時按控制元件寬度計算 num = int((self.w - self.padding_width * 2 - self.collbar_width_y) / self.char_width) else: #不折行時按最長的行所含字元算 texts = self.text.split("\n") for text in texts: if len(text) > num: num = len(text) return num #計算可以一次性展示的行數 def getShowLineNum(self): lostHeight = self.h - 2 * self.padding_height; num = int(lostHeight // self.char_height) return num #計算所有行數 def getTotalLineNum(self): texts = self.text.split("\n") if self.line_wrap == True: k = 0 for i,mytext in enumerate(texts): while len(mytext) > self.max_field_num: submytext = mytext[0:self.max_field_num] mytext = mytext[self.max_field_num:] k += 1 k += 1 return k else: return len(texts) #計算可以一次性展示的列數 def getShowFieldNum(self): lostWidth = self.w - 2 * self.padding_width - self.collbar_width_y; num = int(lostWidth // self.char_width) return num #計算最長的行的列數 def getTotalFieldNum(self): num = 0 if self.line_wrap == True: #折行時按控制元件寬度計算 num = int((self.w - self.padding_width * 2 - self.collbar_width_y) / self.char_width) else: #不折行時按最長的行所含字元算 texts = self.text.split("\n") for text in texts: if len(text) > num: num = len(text) return num def getTrueLineTexts(self): res = [] texts = self.text.split("\n") k = 0 for i,mytext in enumerate(texts): while len(mytext) > self.max_field_num: submytext = mytext[0:self.max_field_num] res.append(submytext) mytext = mytext[self.max_field_num:] k += 1 k += 1 res.append(mytext) return res def draggingyMe(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if self.x + self.w > event.pos[0] > self.x and self.y + self.h > event.pos[1] > self.y: self.dragging_x = True self.startx = event.pos[0] self.dragging_y = True self.starty = event.pos[1] elif event.type == pygame.MOUSEBUTTONUP: if self.x + self.w > event.pos[0] > self.x and self.y + self.h > event.pos[1] > self.y: self.dragging_x = False self.endx = event.pos[0] self.dragging_y = False self.endy = event.pos[1] elif event.type == pygame.MOUSEMOTION: if self.x + self.w > event.pos[0] > self.x and self.y + self.h > event.pos[1] > self.y: self.endx = event.pos[0] self.endy = event.pos[1] if self.dragging_x and self.collbar_width_x > 0: maxoffset = self.w - self.padding_width * 2 - self.collbar_width_y - self.collbar_width_x offset = self.endx - self.startx if offset <= 0: self.collbar_offset_x = 0 elif offset >= maxoffset: self.collbar_offset_x = maxoffset else: self.collbar_offset_x = offset if self.dragging_y and self.collbar_height_y > 0: maxoffset = self.h - self.padding_height * 2 - self.collbar_height_x - self.collbar_height_y offset = self.endy - self.starty if offset <= 0: self.collbar_offset_y = 0 elif offset >= maxoffset: self.collbar_offset_y = maxoffset else: self.collbar_offset_y = offset def draw(self, win): pygame.draw.rect(win, self.color, (self.x, self.y, self.w, self.h)) if self.border_width > 0: pygame.draw.rect(win, self.border_color, (self.x, self.y, self.w, self.h), self.border_width) #右側滑動條 if self.collbar_height_y > 0: pygame.draw.rect(win, self.collbar_bgcolor, (self.x+self.w-self.collbar_width_y-self.padding_width, self.y+self.padding_height, self.collbar_width_y, self.h-2*self.padding_height)) pygame.draw.rect(win, self.collbar_color, (self.x+self.w-self.collbar_width_y-self.padding_width, self.y+self.padding_height+self.collbar_offset_y, self.collbar_width_y, self.collbar_height_y)) #左側滑動條 if self.collbar_width_x > 0: pygame.draw.rect(win, self.collbar_bgcolor, (self.x+self.padding_width, self.y+self.h-self.padding_height-self.collbar_height_x, self.w-2*self.padding_width-self.collbar_width_y, self.collbar_height_x)) pygame.draw.rect(win, self.collbar_color, (self.x+self.padding_width+self.collbar_offset_x, self.y+self.h-self.padding_height-self.collbar_height_x, self.collbar_width_x, self.collbar_height_x)) test_texts = self.getTrueLineTexts() #顯示哪些行 cutPreLineNum = int(self.collbar_offset_y / self.collbar_percent_y // self.char_height) test_texts = test_texts[cutPreLineNum:] #顯示哪些列 showFieldNum = self.getShowFieldNum() cutPreFieldNum = int(self.collbar_offset_x / self.collbar_percent_x // self.char_width) for i,test_text in enumerate(test_texts): test_texts[i] = test_text[cutPreFieldNum:cutPreFieldNum+showFieldNum] texts = '\n'.join(test_texts).split("\n") k = 0 for i,mytext in enumerate(texts): while len(mytext) > self.max_field_num: submytext = mytext[0:self.max_field_num] subtext = self.my_font.render(submytext, True, self.text_color) submyx = self.x + self.padding_width submyy = self.y + self.padding_height + self.char_height * k if submyy+self.char_height < self.y+self.h-self.collbar_height_x: win.blit(subtext, (submyx, submyy)) mytext = mytext[self.max_field_num:] k += 1 text = self.my_font.render(mytext, True, self.text_color) myx = self.x + self.padding_width myy = self.y + self.padding_height + self.char_height * k if myy+self.char_height < self.y+self.h-self.collbar_height_x: win.blit(text, (myx, myy)) k += 1 bt = Button(5, 5, 80, 25) bt.setText('測試按鈕') bt.setColor('Brown') bt.setTextColor('Gold') bt.setBorderColor('Lime') bt.setBorderWidth(1) label_text = ''' 壹哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈壹 貳哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈貳 叄哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈叄 肆哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈肆 伍哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈伍 陸哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈陸 柒哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈柒 '''.strip() label = Label(115, 5, 400, 100) label.setColor('Maroon') label.setText(label_text) label.setTextSize(18) label.setBorderColor('Lime') label.setBorderWidth(1) my_text1 = ''' 壹哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈壹 貳哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈貳 叄哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈叄 肆哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈肆 伍哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈伍 陸哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈陸 柒哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈柒 '''.strip() textArea1 = TextArea(535, 5, 400, 145, my_text1, 18) textArea1.setColor('white') textArea1.setBorderColor('Lime') textArea1.setBorderWidth(1) my_text2 = ''' 壹哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈壹 貳哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈貳 叄哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈叄 肆哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈肆 伍哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈伍 陸哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈陸 柒哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈柒 '''.strip() textArea2 = TextArea(535, 175, 300, 105, my_text2, 14) textArea2.setColor('white') textArea2.setBorderColor('Lime') textArea2.setBorderWidth(1) running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False textArea1.draggingyMe(event) textArea2.draggingyMe(event) if bt.click(event): showMsg("%s被點選了" % bt.getText()) keys_pressed = pygame.key.get_pressed() #ESC鍵 if keys_pressed[pygame.K_ESCAPE]: running = False screen.fill("purple") bt.draw(screen) label.draw(screen) textArea1.draw(screen) textArea2.draw(screen) #更新顯示 pygame.display.flip() #pygame.display.update() dt = clock.tick(60) / 600 pygame.quit()
效果: