pygame - 页面向下滚动
我的程序简单来说是一个联系人应用,这意味着用户需要在应用里存储多个联系人。这样一来,联系人就会超出屏幕显示范围,所以我需要能够向下滚动页面,这样用户才能看到所有联系人,并与特定的联系人进行互动。
不过,我现在遇到了一些麻烦……我该怎么做呢?我面临的问题是,应用的宽度和高度是固定的,所以我不能向下滚动页面,结果发现背景变成黑色,因为我的矩形只设置成和应用窗口的长度一样长。另一个问题是,我不知道怎么“推动”屏幕向上。我完全没有头绪。
这是我目前的程序代码:
import pickle
import operator
import pygame
import sys
from pygame.locals import *
from itertools import groupby
#create Contact class
class Contact():
def __init__(self, firstName, lastName, address, groupType,
telephone, mobile, email, photoField):
self.firstName = firstName
self.lastName = lastName
self.address = address
self.groupType = groupType
self.telephone = telephone
self.mobile = mobile
self.email = email
self.photoField = photoField
def showDetails(self):
print("First Name:\t", self.firstName)
print("Last Name:\t", self.lastName)
print("Address:\t", self.address)
print("Telephone:\t", self.telephone)
print("Mobile:\t", self.mobile)
print("Email:\t", self.email)
@classmethod
def from_input(cls):
firstName = input("First Name: ")
lastName = input("Last Name: ")
address = input("Address: ")
telephone = input("Telephone: ")
mobile = input("Mobile: ")
email = input("Email: ")
return cls(firstName, lastName, address, None,
telephone, mobile, email, None)
class AddressBook():
def __init__(self):
self.contactsList = pickle.load(open("save.p", "rb"))
def addContact(self, contact = None):
if contact is None:
contact = Contact.from_input()
self.contactsList.append(contact)
pickle.dump(self.contactsList, open("save.p", "wb"))
def delContact(self, contact = None):
if contact is None:
search = input("Search: ")
for i in self.contactsList:
if (i.firstName.lower() == search.lower()) or (i.lastName.lower() == search.lower()):
indexed = self.contactsList.index(i)
del self.contactsList[indexed]
pickle.dump(self.contactsList, open("save.p", "wb"))
elif (i.firstName.lower() != search.lower()) or (i.lastName.lower() != search.lower()):
continue
def contactInfo(self, contact = None):
if contact is None:
search = input("Search: ")
print()
#display contact information
for i in self.contactsList:
if (i.firstName.lower() == search.lower()) or (i.lastName.lower() == search.lower()):
i.showDetails()
print()
elif (i.firstName.lower() != search.lower()) or (i.lastName.lower() != search.lower()):
continue
else:
print("No contacts\n")
def contactSearch(self, contact = None):
if contact is None:
search = input("Search: ")
print()
for i in self.contactsList:
if (i.firstName.lower() == search.lower()) or (i.lastName.lower() == search.lower()):
print(i.firstName, i.lastName)
print()
elif (i.firstName.lower() != search.lower()) or (i.lastName.lower() != search.lower()):
continue
else:
print("No contacts\n")
class Page():
def __init__(self, screen = pygame.display.set_mode((320, 480)), caption = pygame.display.set_caption("Contacts")):
self.screen = screen
self.caption = caption
def style(self):
pygame.draw.rect(self.screen, (171,0,0), (0,0,320,63), 0)
pygame.draw.rect(self.screen, (230,230,230), (0,63,320,417), 0)
pygame.draw.line(self.screen, (120,0,0), (5,61), (320, 61), 2)
class MainPage(Page):
def __init__(self, screen = pygame.display.set_mode((320, 480)), caption = pygame.display.set_caption("Contacts"), title = "Contacts"):
Page.__init__(self, screen, caption)
self.title = title
def style(self):
Page.style(self)
titleFont = pygame.font.SysFont("trebuchet ms", 38)
textSurface = titleFont.render(self.title, True, (255,255,255))
self.screen.blit(textSurface, (5, 18))
AddButton().shape()
def printContacts(self):
addressBook = AddressBook()
addressBook.contactsList
addressBook.contactsList.sort(key = lambda c: (c.lastName, c.firstName) if c.lastName else (c.firstName, ""))
contactFont = pygame.font.SysFont("trebuchet ms", 18)
y = 80
for (key, g) in groupby(addressBook.contactsList, lambda c: c.lastName[0] if c.lastName else c.firstName[0]):
groupName = contactFont.render(key, True, (171,0,0))
self.screen.blit(groupName, (5, y))
pygame.draw.line(self.screen, (0,0,0), (5,(y+20)), (320, (y+20)), 1)
y += 30
for i in g:
name = i.firstName + " " + i.lastName
textName = contactFont.render(name, True, (0,0,0))
pygame.draw.line(self.screen, (210,210,210), (5,(y+20)), (320, (y+20)), 1)
self.screen.blit(textName, (5, y))
y += 30
class AddPage(Page):
def __init__(self, screen = pygame.display.set_mode((320, 480)), caption = pygame.display.set_caption("Contacts"), title = "Add Contact"):
Page.__init__(self, screen, caption)
self.title = title
def style(self):
Page.style(self)
titleFont = pygame.font.SysFont("trebuchet ms", 38)
textSurface = titleFont.render(self.title, True, (255,255,255))
self.screen.blit(textSurface, (5, 18))
AddButton().shape()
CancelButton().shape()
class Button():
def __init__(self, screen = pygame.display.set_mode((320, 480))):
self.screen = screen
def shape(self):
pygame.draw.rect(self.screen, (120,0,0), (270,12,40,40), 0)
class AddButton(Button):
def __init__(self, screen = pygame.display.set_mode((320, 480))):
Button.__init__(self, screen)
def shape(self):
Button.shape(self)
pygame.draw.line(self.screen, (255,255,255), (289, 15), (289,48), 2)
pygame.draw.line(self.screen, (255,255,255), (272, 31.5), (307, 31.5), 2)
class CancelButton(Button):
def __init__(self, screen = pygame.display.set_mode((320, 480))):
Button.__init__(self, screen)
def shape(self):
pygame.draw.rect(self.screen, (120,0,0), (245,20,25,25), 0)
pygame.draw.aaline(self.screen, (255,255,255), (252,32.5), (263,26))
pygame.draw.aaline(self.screen, (255,255,255), (252,32.5), (263,39))
pygame.init()
page = MainPage()
page.style()
page.printContacts()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN and event.key == K_ESCAPE:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONUP and event.button == 1 and isinstance(page, MainPage):
if (pygame.mouse.get_pos() >= (270,13)) and (pygame.mouse.get_pos() >= (270,53)) and (pygame.mouse.get_pos() <= (309,13)) and (pygame.mouse.get_pos() <= (309,53)):
page = AddPage()
page.style()
elif event.type == MOUSEBUTTONUP and event.button == 1 and isinstance(page, AddPage):
if (pygame.mouse.get_pos() >= (270,13)) and (pygame.mouse.get_pos() >= (270,53)) and (pygame.mouse.get_pos() <= (309,13)) and (pygame.mouse.get_pos() <= (309,53)):
page = MainPage()
page.style()
page.printContacts()
elif (pygame.mouse.get_pos() >= (245,20)) and (pygame.mouse.get_pos() >= (245,45)) and (pygame.mouse.get_pos() <= (370,20)) and (pygame.mouse.get_pos() <= (370,45)):
page = MainPage()
page.style()
page.printContacts()
pygame.display.update()
addressBook = AddressBook()
addressBook.contactsList
addressBook.contactsList.sort(key = lambda c: (c.lastName, c.firstName) if c.lastName else (c.firstName, ""))
print("-------------------\nContacts\n")
for i in addressBook.contactsList:
print(i.firstName, i.lastName)
print()
print("Menu:\n\n1. Add Contact\n2. Show Contact Details\n3. Edit Contact\n4. Delete Contact\n5. Search Contact\n-------------------\n")
choice = input()
print()
if choice == "1":
#add contacts
contact = AddressBook().addContact()
elif choice == "2":
contact = AddressBook().contactInfo()
elif choice == "4":
contact = AddressBook().delContact()
elif choice == "5":
contact = AddressBook().contactSearch()
else:
continue
我为混合使用pygame代码和原始python代码感到抱歉,因为我还没有完全把shell代码转成pygame能用的代码。所以联系人条目等还是通过Shell/控制台来完成的。我想先完成主屏幕,然后再继续实现通过pygame输入的功能。
1 个回答
10
正如furas在评论中提到的,使用像Tkinter或PyQt这样的图形用户界面(GUI)框架会更好,特别是如果你继续使用pygame,文本输入会让你非常头疼。虽然pygame有一些小部件库,但在我看来,它们都比不上真正的GUI框架。
不过,有一种简单的方法可以为你的应用程序添加滚动功能。你可以不直接把内容画到屏幕上,而是先把它画到一个比屏幕更高的中间Surface
上。如果你想向下滚动,只需把这个中间Surface
放在屏幕Surface
的“上面”。
下面是一个使用鼠标滚轮滚动的简单示例:
import pygame
import string
pygame.init()
screen = pygame.display.set_mode((300, 300))
intermediate = pygame.surface.Surface((300, 600))
i_a = intermediate.get_rect()
x1 = i_a[0]
x2 = x1 + i_a[2]
a, b = (255, 0, 0), (60, 255, 120)
y1 = i_a[1]
y2 = y1 + i_a[3]
h = y2-y1
rate = (float((b[0]-a[0])/h),
(float(b[1]-a[1])/h),
(float(b[2]-a[2])/h)
)
for line in range(y1,y2):
color = (min(max(a[0]+(rate[0]*line),0),255),
min(max(a[1]+(rate[1]*line),0),255),
min(max(a[2]+(rate[2]*line),0),255)
)
pygame.draw.line(intermediate, color, (x1, line),(x2, line))
y = 20
f = pygame.font.SysFont('', 17)
for l in string.ascii_uppercase:
intermediate.blit(f.render(l, True, (255, 255, 255)), (10, y))
y += 20
clock = pygame.time.Clock()
quit = False
scroll_y = 0
while not quit:
quit = pygame.event.get(pygame.QUIT)
for e in pygame.event.get():
if e.type == pygame.MOUSEBUTTONDOWN:
if e.button == 4: scroll_y = min(scroll_y + 15, 0)
if e.button == 5: scroll_y = max(scroll_y - 15, -300)
screen.blit(intermediate, (0, scroll_y))
pygame.display.flip()
clock.tick(60)