鱼C论坛

 找回密码
 立即注册
查看: 1036|回复: 7

[已解决]为何此文本在右上角

[复制链接]
发表于 2023-5-1 07:47:38 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
代码太长,我没写注释,问chatgpt他说我代码太长不肯回我
import pygame
from selenium import webdriver
from requests import get
from subprocess import getstatusoutput as _gsout
from threading import Thread, Timer
from os import remove
from os.path import isfile
from pickle import load, dump
from time import sleep
from bs4 import BeautifulSoup
from lxml import html

pygame.init()
pygame.key.set_repeat(1000, 50)

class Button(pygame.sprite.Sprite):
    def __init__(self, name, size, font: pygame.font.Font, bgc, fgc, pos, key='\0'):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface(size)
        self.image.fill(bgc)
        surf = font.render(name, False, fgc)
        rect = surf.get_rect()
        rect.center = self.image.get_rect().center
        self.image.blit(surf, rect)
        self.rect = self.image.get_rect()
        self.rect.topleft = pos
        self.key = key
        self.font = font
        self.bgc = bgc
        self.fgc = fgc
    
    def chosen(self, event: pygame.event.Event):
        if event.type == pygame.MOUSEBUTTONUP:
            if self.rect.collidepoint(event.pos):
                return True
        if event.type == pygame.KEYDOWN:
            if event.key == ord(self.key) and event.mod & pygame.KMOD_ALT:
                return True
        return False

    def draw(self):
        screen.blit(self.image, self.rect)

class Text(pygame.sprite.Sprite):
    def __init__(self, text, font, color, pos):
        pygame.sprite.Sprite.__init__(self)
        self.font = font
        self._text = text
        self.color = color
        self.image = self.font.render(self.text, False, self.color)
        self.rect = self.image.get_rect()
        self.rect.topleft = pos
    
    def draw(self):
        screen.blit(self.image, self.rect)

    @property
    def text(self):
        return self._text

    @text.setter
    def text(self, new):
        self._text = new
        self.image = self.font.render(self.text, False, self.color)

class Entry(pygame.sprite.Sprite):
    def __init__(self, size, font, bgc, bdc, fgc, pos):
        pygame.sprite.Sprite.__init__(self)
        self.bgc = bgc
        self.bdc = bdc
        self.image = pygame.Surface(size)
        self.image.fill(bgc)
        for x in range(0, size[0]):
            self.image.set_at((x, 0), bdc)
            self.image.set_at((x, size[1] - 1), bdc)
        for y in range(0, size[1]):
            self.image.set_at((0, y), bdc)
            self.image.set_at((size[0] - 1, y), bdc)
        self.text = Text('', font, fgc, pos)
        self.image.blit(self.text.image, (0, 0))
        self.rect = self.image.get_rect()
        self.rect.topleft = pos
        self.selected = False
    
    @property
    def fgc(self):
        return self.text.color

    def draw(self):
        screen.blit(self.image, self.rect)
    
    def listen(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            self.selected = self.rect.collidepoint(event.pos)
        elif event.type == pygame.KEYDOWN:
            if self.selected:
                if event.key == pygame.K_BACKSPACE:
                    self.text.text = self.text.text[:-1]
                    self._update_text()
                elif (event.unicode in 
                    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+[];,./{}|:"<>?'
                    + "'" + '\\'
                ):
                    self.text.text += event.unicode
                    self._update_text()
    
    def _update_text(self):
        size = self.rect.size
        self.image = pygame.Surface(size)
        self.image.fill(self.bgc)
        for x in range(0, size[0]):
            self.image.set_at((x, 0), self.bdc)
            self.image.set_at((x, size[1] - 1), self.bdc)
        for y in range(0, size[1]):
            self.image.set_at((0, y), self.bdc)
            self.image.set_at((size[0] - 1, y), self.bdc)
        self.text = Text(self.text.text, self.text.font, self.fgc, self.rect.topleft)
        self.image.blit(self.text.image, (0, 0))

class PasswordEntry(Entry):
    def _update_text(self):
        size = self.rect.size
        self.image = pygame.Surface(size)
        self.image.fill(self.bgc)
        for x in range(0, size[0]):
            self.image.set_at((x, 0), self.bdc)
            self.image.set_at((x, size[1] - 1), self.bdc)
        for y in range(0, size[1]):
            self.image.set_at((0, y), self.bdc)
            self.image.set_at((size[0] - 1, y), self.bdc)
        self.text = Text(len(self.text.text) * '*', self.text.font, self.fgc, self.rect.topleft)
        self.image.blit(self.text.image, (0, 0))

class MyThread(Thread):
    def __init__(self, func, args=(), kwargs=None, timeout=None):
        Thread.__init__(self)
        self.func = func
        self.args = args
        self.kwargs = {} if kwargs is None else kwargs
        self.timeout = timeout
        self.result = None
    
    def run(self):
        self.result = self.func(*self.args, **self.kwargs)

def timeout(seconds):
    def decorated(func):
        def done(*args, **kwargs):
            err = None
            result = None
            def inner():
                nonlocal err, result
                try:
                    result = func(*args, **kwargs)
                except BaseException as msg:
                    err = msg
            thread = Thread(target=inner)
            thread.start()
            # 只等待seconds秒
            thread.join(seconds)
            # 如果线程还活着
            if thread.is_alive():
                raise TimeoutError
            if err:
                raise err
            return result
        return done
    return decorated

# 实际上是生成了一个新的decorated函数,通过闭包的形式保存了秒数,然后done里再调用inner
@timeout(1)
def soutf(msg):
    return _gsout(msg)

def check_internet():
    try:
        soutf('ping fishc.com.cn')
        # 这东西,报错可是最快
        print('你没联网')
        exit()
    except TimeoutError:
        # 连上了的话那就好说
        pass

def load_image(url):
    filename = 'temp.png'
    with open(filename, 'wb') as f:
        f.write(get(url, headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
        }).content)
    image = pygame.image.load(filename)
    remove(filename)
    return image

def save():
    with open('fishc.set', 'wb') as f:
        dump(data, f)

def loginf(email, password):
    driver.get('https://fishc.com.cn/member.php?mod=logging&action=login')
    sleep(1)
    driver.find_element(
        'xpath',
        '/html/body/div[6]/div/div[2]/div/div[2]/div[1]/div[1]/form/div/div[1]/table/tbody/tr/td[1]/input'
    ).send_keys(email)
    driver.find_element(
        'xpath',
        '/html/body/div[6]/div/div[2]/div/div[2]/div[1]/div[1]/form/div/div[2]/table/tbody/tr/td[1]/input'
    ).send_keys(password)
    driver.find_element(
        'xpath',
        '/html/body/div[6]/div/div[2]/div/div[2]/div[1]/div[1]/form/div/div[6]/table/tbody/tr/td[1]/button'
    ).click()
    sleep(1)
    driver.find_element('id', 'succeedmessage_href').click()
    return driver.page_source

def getdata(source):
    tree = html.fromstring(source)
    part = html.tostring(tree.xpath('//strong[@class="vwmy"]')[0], encoding='unicode')
    usergroup = html.tostring(tree.xpath('//a[@id="g_upmine"]')[0], encoding='unicode')
    soup = BeautifulSoup(part, features='lxml')
    soup2 = BeautifulSoup(usergroup, features='lxml')
    return soup.find('a').text, soup2.find('font').get('color'), soup2.find('font').text

def login_to1(email, password):
    return getdata(loginf(email, password))

def login_to(email, password):
    result = login_to1(email, password)
    Timer(3, hide_msg).start()
    return result

def hide_msg():
    global state
    state = 3

check_internet()

size = width, height = (640, 480)
screen = pygame.display.set_mode(size)
logo = load_image('https://fishc.com.cn/static/image/common/logo.png')
icon = load_image('https://fishc.com.cn/favicon.ico')
pygame.display.set_caption('FishC App')
pygame.display.set_icon(icon)
font15 = pygame.font.SysFont('microsoftyaheiui', 15)
font20 = pygame.font.SysFont('microsoftyaheiui', 20)
font20b = pygame.font.SysFont('microsoftyaheiui', 20)
font20b.set_bold(True)
chrome = Button('[C]hrome', (100, 50), font20, (0, 255, 0), (0, 0, 0), (100, 200), 'c')
firefox = Button('[F]irefox', (100, 50), font20, (0, 255, 0), (0, 0, 0), (300, 200), 'f')
c_chrome = Button('Change driver(Using Chrome)', (200, 50), font15, (255, 255, 255), (0, 0, 0), (width - 200, 0))
c_firefox = Button('Change driver(Using Firefox)', (200, 50), font15, (255, 255, 255), (0, 0, 0), (width - 200, 0))
change = c_chrome
login = Button('登录(L)', (100, 50), font20, (0, 0, 255), (255, 255, 255), (width - 123, height - 100), 'l')
save1 = Button('保存数据(S)', (150, 50), font20, (0, 0, 255), (255, 255, 255), (width // 2 - 125, height // 2 - 50), 's')
unsave = Button('不保存数据(N)', (150, 50), font20, (0, 0, 255), (255, 255, 255), (width // 2 - 125, height // 2 + 50), 'n')
swin = pygame.Rect(width // 4, height // 4, width // 2, height // 2)
username = Entry((200, 30), font20, (255, 255, 255), (0, 0, 127), (0, 0, 0), (200, 100))
pwd = Entry((200, 30), font20, (255, 255, 255), (0, 0, 127), (0, 0, 0), (200, 180))
t_user = Text('用户名/邮箱', font20b, (0, 0, 0), (90, 100))
t_pwd = Text('密码', font20b, (0, 0, 0), (100, 180))
logining = Text('', font15, (0, 0, 0), (300, 200))
succed = Text('', font15, (0, 0, 0), (width - 150, 10))

data = {
    'driver': None,
    'username': None,
    'password': None
}
state = 0
if isfile('fishc.set'):
    with open('fishc.set', 'rb') as f:
        data = load(f)
thread = None

clock = pygame.time.Clock()
running = True
while running:
    clock.tick(30)
    screen.fill((255, 255, 255))
    screen.blit(logo, (0, 0))
    if state == 1:
        pygame.draw.rect(screen, (0, 0, 0), swin, 2)
        save1.draw()
        unsave.draw()
    elif state == 0:
        if data['driver'] is None:
            chrome.draw()
            firefox.draw()
        else:
            change.draw()
            if data['username'] is None or data['password'] is None:
                username.draw()
                t_user.draw()
                pwd.draw()
                t_pwd.draw()
                login.draw()
    elif state == 2:
        if thread.result is None:
            logining.text = '登录中...'
        else:
            logining.text = '登录成功!'
        logining.draw()
    elif state == 3:
        succed.text = f'{thread.result[0]}(用户组: {thread.result[2]})'
        succed.color = thread.result[1]
        succed.rect.topleft = (width - succed.rect.width - 10, 10)
        succed.draw()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            if state == 1:
                running = False
                # 虽然只会退出for
                break
            state = 1
        if state == 1:
            if save1.chosen(event):
                save()
                running = False
            elif unsave.chosen(event):
                running = False
        else:
            if data['driver'] is None:
                temp = False
                if chrome.chosen(event):
                    data['driver'] = (webdriver.Chrome, webdriver.ChromeOptions)
                    change = c_chrome
                    temp = True
                elif firefox.chosen(event):
                    data['driver'] = (webdriver.Firefox, webdriver.FirefoxOptions)
                    change = c_firefox                
                    temp = True
                if temp:
                    option = data['driver'][1]()
                    option.add_argument('headless')
                    driver = data['driver'][0](options=option)
            else:
                if data['username'] is None or data['password'] is None:
                    username.listen(event)
                    pwd.listen(event)
                if change.chosen(event):
                    data['driver'] = None
                if login.chosen(event):
                    data['username'] = username.text.text
                    data['password'] = pwd.text.text
                    state = 2
                    thread = MyThread(func=login_to, args=(username.text.text, pwd.text.text))
                    thread.start()
    pygame.display.flip()
pygame.quit()
driver.close()
就这么一个文件
main1.zip (3.61 KB, 下载次数: 1)
picture: 捕获.PNG
最佳答案
2023-5-1 08:14:32

抱歉,看起来是文本的渲染方式导致的。为了使文本更精确地居中,可以在绘制文本前计算文本宽度的一半,并将其减去屏幕宽度的一半。这样可以确保文本在屏幕中心位置上。修改代码如下:

1. 在  Text  类中添加一个方法  draw_centered ,用于计算并绘制居中的文本:
class Text:
    # 省略其他代码...

    def draw_centered(self, surface):
        self.surface = self.font.render(self.text, True, self.color)
        self.rect = self.surface.get_rect()
        self.rect.center = (width // 2, height // 2)
        surface.blit(self.surface, self.rect.topleft)

2. 更新  state == 3  的情况,使用新的  draw_centered  方法绘制居中的文本:
elif state == 3:
    succed.text = f'{thread.result[0]}(用户组: {thread.result[2]})'
    succed.color = thread.result[1]
    succed.draw_centered(screen)

这样,当登录成功后,用户名和用户组信息将准确显示在屏幕正中间。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-5-1 07:56:01 | 显示全部楼层
从您提供的代码来看,登录成功后,用户名显示在右上角是由以下代码实现的:
succed = Text('', font15, (0, 0, 0), (width - 150, 10))

这行代码创建了一个名为  succed  的  Text  对象,将其初始位置设置为屏幕右上角附近。具体来说, width - 150  使文本距离屏幕右侧 150 像素, 10  则是距离屏幕顶部的像素数。当登录成功时, state  变为 3,下面的代码将用户名和用户组信息显示在屏幕上:
elif state == 3:
    succed.text = f'{thread.result[0]}(用户组: {thread.result[2]})'
    succed.color = thread.result[1]
    succed.rect.topleft = (width - succed.rect.width - 10, 10)
    succed.draw()

在这段代码中,首先更新  succed  的文本属性,包括用户名和用户组信息。接着,根据文本的宽度,重新计算并设置文本的位置,使其始终保持在屏幕右上角附近。最后调用  succed.draw()  方法将文本绘制在屏幕上。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-1 08:00:28 | 显示全部楼层
isdkz 发表于 2023-5-1 07:56
从您提供的代码来看,登录成功后,用户名显示在右上角是由以下代码实现的:

似乎并没有回答问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-1 08:03:21 | 显示全部楼层

要将用户名显示在屏幕正中间,首先需要在每次更新文本内容时计算正确的位置。可以通过以下方法调整代码来实现:

1. 修改  succed  对象的初始化位置,使其在屏幕正中间。这里,我们将其位置设置为  (width // 2, height // 2) :
succed = Text('', font15, (0, 0, 0), (width // 2, height // 2))

2. 在登录成功时,更新  succed  对象的位置,使其始终保持在屏幕正中间:
elif state == 3:
    succed.text = f'{thread.result[0]}(用户组: {thread.result[2]})'
    succed.color = thread.result[1]
    succed.rect.center = (width // 2, height // 2)
    succed.draw()

这里,我们将  succed.rect.topleft  替换为  succed.rect.center ,并将其位置设置为屏幕中心点  (width // 2, height // 2) 。这样,在登录成功后,用户名和用户组信息将显示在屏幕正中间。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-1 08:09:29 | 显示全部楼层
isdkz 发表于 2023-5-1 08:03
要将用户名显示在屏幕正中间,首先需要在每次更新文本内容时计算正确的位置。可以通过以下方法调整代码来 ...

捕获.PNG
pictrue.png
也不是正中间啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-1 08:14:32 | 显示全部楼层    本楼为最佳答案   

抱歉,看起来是文本的渲染方式导致的。为了使文本更精确地居中,可以在绘制文本前计算文本宽度的一半,并将其减去屏幕宽度的一半。这样可以确保文本在屏幕中心位置上。修改代码如下:

1. 在  Text  类中添加一个方法  draw_centered ,用于计算并绘制居中的文本:
class Text:
    # 省略其他代码...

    def draw_centered(self, surface):
        self.surface = self.font.render(self.text, True, self.color)
        self.rect = self.surface.get_rect()
        self.rect.center = (width // 2, height // 2)
        surface.blit(self.surface, self.rect.topleft)

2. 更新  state == 3  的情况,使用新的  draw_centered  方法绘制居中的文本:
elif state == 3:
    succed.text = f'{thread.result[0]}(用户组: {thread.result[2]})'
    succed.color = thread.result[1]
    succed.draw_centered(screen)

这样,当登录成功后,用户名和用户组信息将准确显示在屏幕正中间。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-1 08:35:37 | 显示全部楼层
isdkz 发表于 2023-5-1 08:14
抱歉,看起来是文本的渲染方式导致的。为了使文本更精确地居中,可以在绘制文本前计算文本宽度的一半,并 ...

看你的代码知道为什么了

评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
Threebody1 + 1 + 1 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-1 08:44:59 | 显示全部楼层
isdkz 发表于 2023-5-1 08:14
抱歉,看起来是文本的渲染方式导致的。为了使文本更精确地居中,可以在绘制文本前计算文本宽度的一半,并 ...

是因为text.setter里更新text的时候没更新rect

评分

参与人数 1荣誉 +5 贡献 +3 收起 理由
歌者文明清理员 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-23 11:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表