Python 如何调整按钮的像素大小?(特金特)

Python 如何调整按钮的像素大小?(特金特),python,python-3.x,tkinter,Python,Python 3.x,Tkinter,我正在用Python Tkinter制作一个Tic-Tac-Toe游戏,但是按钮是矩形的,我希望它们的大小都是100x100像素。我尝试使用: a1 = Button(root, text="", font="Helvetica 16 bold", command=a1, height=10, width=10) (忽略空字符串和a1),但它不会将其调整为正方形。我已经编写了大部分代码,不想使用框架来调整它们的大小。我该怎么办?我希望确保按钮的像素大小是特定的,方法是将按钮放在帧内,并确保帧设

我正在用Python Tkinter制作一个Tic-Tac-Toe游戏,但是按钮是矩形的,我希望它们的大小都是100x100像素。我尝试使用:

a1 = Button(root, text="", font="Helvetica 16 bold", command=a1, height=10, width=10)

(忽略空字符串和
a1
),但它不会将其调整为正方形。我已经编写了大部分代码,不想使用框架来调整它们的大小。我该怎么办?

我希望确保按钮的像素大小是特定的,方法是将按钮放在帧内,并确保帧设置为特定大小,按钮设置为填充该帧

这可以很容易地转换为在您的程序中工作,并确保按钮设置为100 x 100

这是我知道的唯一确定按钮大小(以像素为单位)的方法。可能还有其他选择

首先,我们需要两个列表。一个用来固定框架,一个用来固定按钮。这将使我们能够以一种方便的方式存储框架和按钮,以便以后使用

frames_list = []
btn_list = []
我不知道如何压缩你的
check_win()
函数,所以我只对它做一点小的修改,这样它就可以处理列表了。我们需要将
a1
a2
a3
等的每个实例替换为按钮列表中的对应实例,并使用稍后将使用for循环创建的索引值

def check_win():
    # Horizontal wins
    if btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "X" or btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "O":
        print("{} wins".format(btn_list[0]["text"]))
    elif btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "X" or btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "O":
        print("{} wins".format(btn_list[3]["text"]))
    elif btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "X" or btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "O":
        print("{} wins".format(btn_list[6]["text"]))

    # Vertical wins
    elif btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "X" or btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "O":
        print("{} wins".format(btn_list[0]["text"]))
    elif btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "X" or btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "O":
        print("{} wins".format(btn_list[1]["text"]))
    elif btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "X" or btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "O":
        print("{} wins".format(btn_list[2]["text"]))

    # Diagonal wins
    elif btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "X" or btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "O":
        print("{} wins".format(btn_list[0]["text"]))
    elif btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "X" or btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "O":
        print("{} wins".format(btn_list[2]["text"]))

    # If no one wins
    else:
        change_turn()
然后,我们需要更改
process\u turn()
函数,将每个按钮的索引值包含在按钮列表中,以便像这样向其添加一个参数

def process_turn(ndex): # index argument being sent by buttons
    btn_list[ndex].config(text=turn) # changed text at index of list.
    check_win()
最后,我们需要在命令中创建具有正确索引的所有按钮,我们可以使用for循环来实现这一点。2号井用于循环

第一个循环将开始行计数,第二个for循环将进行列计数。这将创建3×3网格。
ndex
变量用于跟踪按钮列表中每个按钮需要配置的索引

def create_frames_and_buttons():
    ndex = 0
    i = 0
    x = 0
    for i in range(3):
        for x in range(3):
            frames_list.append(Frame(root, width = 100, height = 100))
            frames_list[ndex].propagate(False)
            frames_list[ndex].grid(row = i, column = x, sticky = "nsew", padx = 2, pady = 2) # add any padding you would like to space out the frames/buttons
            btn_list.append(Button(frames_list[ndex], text="", font="Helvetica 16 bold",
                   command = lambda ndex=ndex: process_turn(ndex)))
            btn_list[ndex].pack(expand=True, fill=BOTH)
            x += 1
            ndex += 1
        i += 1
    root.resizable(width=False, height=False)

create_frames_and_buttons()
所有这些加在一起,你有这个代码,有确切的100x100像素大小你想要的

请看下面的示例:

from tkinter import *

root = Tk()
frames_list = []
btn_list = []

turn = "X"
turnLabel = Label(root, text=turn, font="Helvetica 16 bold")
turnLabel.grid(row=3, columnspan=3)

def change_turn():
    global turn
    if turn == "O":
        turn = "X"
        turnLabel.config(text=turn)
    elif turn == "X":
        turn = "O"
        turnLabel.config(text=turn)

def check_win():
    # Horizontal wins
    if btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "X" or btn_list[0]["text"] == btn_list[1]["text"] == btn_list[2]["text"] == "O":
        print("{} wins".format(btn_list[0]["text"]))
    elif btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "X" or btn_list[3]["text"] == btn_list[4]["text"] == btn_list[5]["text"] == "O":
        print("{} wins".format(btn_list[3]["text"]))
    elif btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "X" or btn_list[6]["text"] == btn_list[7]["text"] == btn_list[8]["text"] == "O":
        print("{} wins".format(btn_list[6]["text"]))

    # Vertical wins
    elif btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "X" or btn_list[0]["text"] == btn_list[3]["text"] == btn_list[6]["text"] == "O":
        print("{} wins".format(btn_list[0]["text"]))
    elif btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "X" or btn_list[1]["text"] == btn_list[4]["text"] == btn_list[7]["text"] == "O":
        print("{} wins".format(btn_list[1]["text"]))
    elif btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "X" or btn_list[2]["text"] == btn_list[5]["text"] == btn_list[8]["text"] == "O":
        print("{} wins".format(btn_list[2]["text"]))

    # Diagonal wins
    elif btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "X" or btn_list[0]["text"] == btn_list[4]["text"] == btn_list[8]["text"] == "O":
        print("{} wins".format(btn_list[0]["text"]))
    elif btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "X" or btn_list[2]["text"] == btn_list[4]["text"] == btn_list[6]["text"] == "O":
        print("{} wins".format(btn_list[2]["text"]))

    # If no one wins
    else:
        change_turn()

def process_turn(ndex):
    btn_list[ndex].config(text=turn)
    check_win()

def create_frames_and_buttons():
    ndex = 0
    i = 0
    x = 0
    for i in range(3):
        for x in range(3):
            frames_list.append(Frame(root, width = 100, height = 100))
            frames_list[ndex].propagate(False)
            frames_list[ndex].grid(row = i, column = x, sticky = "nsew", padx = 2, pady = 2)
            btn_list.append(Button(frames_list[ndex], text="", font="Helvetica 16 bold",
                   command = lambda ndex=ndex: process_turn(ndex)))
            btn_list[ndex].pack(expand=True, fill=BOTH)
            x += 1
            ndex += 1
        i += 1
    root.resizable(width=False, height=False)

create_frames_and_buttons()

root.mainloop()
结果:


一个简单的方法是给按钮一个不可见的1x1像素图像。执行此操作时,
宽度
高度
属性将被解释为像素(或者更准确地说,屏幕单位,也可以是点、英寸或厘米)

如果执行此操作,可以将
composite
设置为值“c”,表示按钮应同时显示文本和图像,且两者均位于窗口的中心

例如:

import Tkinter as tk
...
pixel = tk.PhotoImage(width=1, height=1)
button = tk.Button(root, text="", image=pixel, width=100, height=100, compound="c")
...

下面是使用自适应算法完成的代码(因此它可以从错误中学习)。在回答您的问题时,我使用了画布并创建了矩形,然后将单击绑定到画布上

DRAW_WEIGHT = 1 # The value for a round where there was a draw
COMPUTER_WIN_WEIGHT = 5 # The value for a round where there was a computer win
COMPUTER_LOSE_WEIGHT = -5 # The value for a round where there was a computer loss
LOG = True # Rounds be logged to improve move knowledge

import ctypes, math, threading, random, os, time, os.path
from tkinter import *

def end (mode, at = None):
    global active, facts
    active = False
    if mode == 0: l.config (text = "Draw")
    elif mode == 1:
        if player == -1: l.config (text = "You lose")
        else: l.config (text = "Player 1 wins")
    else:
        if player == -1: l.config (text = "Well done! You win!")
        else: l.config (text = "Player 2 wins")
    if player == -1:
        log [-1].append (mode)
        if LOG:
            with open ("Learn.log", "w") as f: f.write ("\n".join ([" ".join ([str (j) for j in i]) for i in log]))
        else:
            with open ("Learn.log", "w") as f: f.write ("\n".join ([" ".join ([str (j) for j in i]) for i in log [ : -1]]))
    if at:
        if at [0] == 0: c.create_line (at [1] * 200 + 100, 0, at [1] * 200 + 100, 600, width = 5, fill = "blue")
        elif at [0] == 1: c.create_line (0, at [1] * 200 + 100, 600, at [1] * 200 + 100, width = 5, fill = "blue")
        elif at [0] == 2: c.create_line (0, 0, 600, 600, width = 5, fill = "blue")
        else: c.create_line (600, 0, 0, 600, width = 5, fill = "blue")
    c.create_text (300, 250, text = "Game Over", fill = "red", font = ("times", 75))
    c.create_text (300, 325, text = "Click to play again", fill = "red", font = ("times", 30))
    c.bind ("<Button-1>", restart)

def restart (event = None):
    global places, player
    c.delete (ALL)
    places = [0 for i in range (9)]
    for i in range (2): c.create_line (200 + 200 * i, 0, 200 + 200 * i, 600, width = 2)
    for i in range (2): c.create_line (0, 200 + 200 * i, 600, 200 + 200 * i, width = 2)
    if player == -1:
        l.config (text = "Click on a square to go there")
        c.bind ("<Button-1>", lambda event: threading.Thread (target = click, args = (event,)).start ())
    else:
        player = True
        l.config (text = "Player 1's turn")
        c.bind ("<Button-1>", lambda event: threading.Thread (target = p2click, args = (event,)).start ())

def check (mode = False):
    toGo = (-1,)
    for i in range (3):
        now = [places [i + j * 3] for j in range (3)]
        if now.count (1) == 3:
            toGo = (0, i)
            break
    if toGo [0] == -1:
        for i in range (3):
            now = [places [j + i * 3] for j in range (3)]
            if now.count (1) == 3:
                toGo = (1, i)
                break
    if toGo [0] == -1:
        now = [places [i + i * 3] for i in range (3)]
        if now.count (1) == 3: toGo = (2,)
    if toGo [0] == -1:
        now = [places [2 + i * 3 - i] for i in range (3)]
        if now.count (1) == 3: toGo = (3,)
    if toGo [0] == -1:
        for i in range (3):
            now = [places [i + j * 3] for j in range (3)]
            if now.count (2) == 3:
                toGo = (0, i)
                break
        if toGo [0] == -1:
            for i in range (3):
                now = [places [j + i * 3] for j in range (3)]
                if now.count (2) == 3:
                    toGo = (1, i)
                    break
        if toGo [0] == -1:
            now = [places [i + i * 3] for i in range (3)]
            if now.count (2) == 3: toGo = (2,)
        if toGo [0] == -1:
            now = [places [2 + i * 3 - i] for i in range (3)]
            if now.count (2) == 3: toGo = (3,)
        if toGo [0] == -1:
            if mode: end (0)
            else: return True
        else: end (1, toGo)
    else: end (2, toGo)
    return False

def click (event):
    global log, active, facts
    c.bind ("<Button-1>", lambda event: None)
    start = time.clock ()
    l.config (text = "Calculating...")
    x, y = math.floor (event.x / 200), math.floor (event.y / 200)
    if x == 3: x -= 1
    if y == 3: y -= 1
    if places [x + y * 3] == 0:
        if places.count (0) == 9:
            log.append ([x + y * 3])
            active = True
        else: log [-1].append (x + y * 3)
        places [x + y * 3] = 1
        c.create_line (x * 200 + 25, y * 200 + 25, x * 200 + 175, y * 200 + 175, width = 2)
        c.create_line (x * 200 + 25, y * 200 + 175, x * 200 + 175, y * 200 + 25, width = 2)
        toGo, movesChecked = -1, 0
        if places.count (0) == 0: check (True)
        else:
            if check ():
                for i in range (3):
                    movesChecked += 1
                    now = [places [i + j * 3] for j in range (3)]
                    if now.count (2) == 2 and now.count (0) == 1:
                        toGo = i + now.index (0) * 3
                        break
                if toGo == -1:
                    for i in range (3):
                        movesChecked += 1
                        now = [places [j + i * 3] for j in range (3)]
                        if now.count (2) == 2 and now.count (0) == 1:
                            toGo = now.index (0) + i * 3
                            break
                if toGo == -1:
                    movesChecked += 1
                    now = [places [i + i * 3] for i in range (3)]
                    if now.count (2) == 2 and now.count (0) == 1: toGo = now.index (0) + now.index (0) * 3
                if toGo == -1:
                    movesChecked += 1
                    now = [places [2 + i * 3 - i] for i in range (3)]
                    if now.count (2) == 2 and now.count (0) == 1: toGo = 2 + now.index (0) * 3 - now.index (0)
                if toGo == -1:
                    for i in range (3):
                        movesChecked += 1
                        now = [places [i + j * 3] for j in range (3)]
                        if now.count (1) == 2 and now.count (0) == 1:
                            toGo = i + now.index (0) * 3
                            break
                if toGo == -1:
                    for i in range (3):
                        movesChecked += 1
                        now = [places [j + i * 3] for j in range (3)]
                        if now.count (1) == 2 and now.count (0) == 1:
                            toGo = now.index (0) + i * 3
                            break
                if toGo == -1:
                    movesChecked += 1
                    now = [places [i + i * 3] for i in range (3)]
                    if now.count (1) == 2 and now.count (0) == 1: toGo = now.index (0) + now.index (0) * 3
                if toGo == -1:
                    movesChecked += 1
                    now = [places [2 + i * 3 - i] for i in range (3)]
                    if now.count (1) == 2 and now.count (0) == 1: toGo = 2 + now.index (0) * 3 - now.index (0)
                if toGo == -1:
                    useful = [0, 0, 0, 0, 0, 0, 0, 0, 0]
                    for rot in range (4):
                        for i in range (len (log) - 1):
                            movesChecked += 1
                            this = rotate (log [i], rot)
                            if len (log [i]) > len (log [-1]):
                                if log [-1] == this [ : len (log [-1])]:
                                    if this [-1] == 0: value = DRAW_WEIGHT
                                    elif this [-1] == 1: value = COMPUTER_WIN_WEIGHT
                                    else: value = COMPUTER_LOSE_WEIGHT
                                    useful [this [len (log [-1])]] += value
                    toGo = useful.index (max (useful))
                    while places [toGo] != 0:
                        movesChecked += 1
                        useful [toGo] = min (useful) - 1
                        toGo = useful.index (max (useful))
                places [toGo] = 2
                log [-1].append (toGo)
                c.create_oval (toGo % 3 * 200 + 25, math.floor (toGo / 3) * 200 + 25, toGo % 3 * 200 + 175, math.floor (toGo / 3) * 200 + 175, width = 2)
                facts = [round ((time.clock () - start) * 1000, 1), movesChecked]
                facts.append (round (facts [1] / facts [0]))
                if check ():
                    l.config (text = "Your turn")
                    c.bind ("<Button-1>", lambda event: threading.Thread (target = click, args = (event,)).start ())
    else:
        l.config (text = "This square has already been taken.")
        c.bind ("<Button-1>", lambda event: threading.Thread (target = click, args = (event,)).start ())

def nerdyFacts ():
    t = Toplevel ()
    t.focus_force ()
    t.resizable (False, False)
    if os.path.isfile ("icon.ico"): t.iconbitmap ("icon.ico")
    if len (facts) > 0: Label (t, text = "Just a few facts about the last move should you wish to know them:\n%sms taken to process request\n%s possible moves checked\n%s moves checked per ms" % tuple (facts)).pack ()
    else: Label (t, text = "No facts to display.").pack ()

def rotate (data, mode):
    if mode == 0: replace = [i for i in range (9)]
    elif mode == 1: replace = [2, 5, 8, 1, 4, 7, 0, 3, 6]
    elif mode == 2: replace = [8, 7, 6, 5, 4, 3, 2, 1, 0]
    else: replace = [6, 3, 0, 7, 4, 1, 8, 5, 2]
    return [replace [i] for i in data [ : -1]] + [data [-1]]

def remove ():
    global log
    if ctypes.windll.user32.MessageBoxW (0, "Do you really want to delete all of my data.\nIn doing so, I will not be able to make such informed moves.\nOn average, I say it takes about 20 rounds for me to start getting better.\nThis is only recommended if the program takes a long time to make moves.", "Naughts and crosses", 4) == 6:
        if active: del log [ : -1]
        else: log = []
        with open ("Learn.log", "w") as f: f.write ("")
        t.destroy ()
        ctypes.windll.user32.MessageBoxW (0, "Data reset.", "Naughts and crosses", 0)

def p2click (event):
    global player
    x, y = math.floor (event.x / 200), math.floor (event.y / 200)
    if x == 3: x -= 1
    if y == 3: y -= 1
    if places [x + y * 3] == 0:
        places [x + y * 3] = int (player) + 1
        if player:
            c.create_line (x * 200 + 25, y * 200 + 25, x * 200 + 175, y * 200 + 175, width = 2)
            c.create_line (x * 200 + 25, y * 200 + 175, x * 200 + 175, y * 200 + 25, width = 2)
        else: c.create_oval (x * 200 + 25, y * 200 + 25, x * 200 + 175, y * 200 + 175, width = 2)
        l.config (text = "Player %s's turn" % str (int (player) + 1))
        player = not player
        if places.count (0) == 0: check (True)
        else: check ()

def start (players):
    global player
    if players == 1:
        player = -1
        t = Label (root, text = "Data information", font = ("times", 12))
        t.pack ()
        t.bind ("<Button-1>", lambda event: threading.Thread (target = dataLog).start ())
    else: player = True
    restart ()

def dataLog ():
    global t
    t = Toplevel ()
    t.resizable (False, False)
    t.focus_force ()
    if os.path.isfile ("icon.ico"): t.iconbitmap ("icon.ico")
    if active: l = log [ : -1]
    else: l = log
    if len (l) == 0: Label (t, text = "I have no data to analyse.\nTherefore, I cannot display any extra information.").pack ()
    else:
        wins, loses, draws = 0, 0, 0
        for i in l:
            if i [-1] == 0: draws += 1
            elif i [-1] == 1: loses += 1
            else: wins += 1
        wins, loses, draws = round (wins * 100 / len (l)), round (loses * 100 / len (l)), round (draws * 100 / len (l))
        last = math.ceil (len (l) / 2)
        last_wins, last_loses, last_draws = 0, 0, 0
        if last > 50: last = 50
        for i in l [len (l) - last : ]:
            if i [-1] == 0: last_draws += 1
            elif i [-1] == 1: last_loses += 1
            else: last_wins += 1
        last_wins, last_loses, last_draws = round (last_wins * 100 / last), round (last_loses * 100 / last), round (last_draws * 100 / last)
        Label (t, text = "I have %s round/s of data to analyse.\n(%s virtual rounds)\n\nOf these:\n%s%s are user wins\n%s%s are computer wins\n%s%s are draws\n\nIn the last %s round/s:\n%s%s are user wins\n%s%s are computer wins\n%s%s are draws\n" % (len (l), len (l) * 4, wins, "%", loses, "%", draws, "%", last, last_wins, "%", last_loses, "%", last_draws, "%")).pack ()
        Button (t, text = "Clear data", command = lambda: threading.Thread (target = remove).start ()).pack ()

active, facts = False, ()
if os.path.isfile ("Learn.log"):
    with open ("Learn.log") as f:
        read = f.read ()
        if read != "": log = [[int (j) for j in i.split (" ")] for i in read.split ("\n")]
        else: log = []
else: log = []
try: ctypes.windll.shcore.SetProcessDpiAwareness (True)
except: pass
root = Tk ()
root.title ("Naughts and crosses")
root.resizable (False, False)
if os.path.isfile ("icon.ico"): root.iconbitmap ("icon.ico")
l = Label (root, text = "", font = ("times", 20))
l.bind ("<Button-1>", lambda event: nerdyFacts ())
l.pack ()
c = Canvas (root, width = 600, height = 600, bg = "white")
c.pack ()
c.create_text (300, 200, text = "How many players are there?", font = ("times", 30))
p1 = (c.create_rectangle (150, 350, 250, 450, fill = "blue"),
      c.create_text (200, 400, text = "1", font = ("times", 40), fill = "red"))
p2 = (c.create_rectangle (350, 350, 450, 450, fill = "red"),
      c.create_text (400, 400, text = "2", font = ("times", 40), fill = "blue"))
for i in p1: c.tag_bind (i, "<ButtonRelease-1>", lambda event: start (1))
for i in p2: c.tag_bind (i, "<ButtonRelease-1>", lambda event: start (2))
root.mainloop ()

如果使用place方法添加按钮,则可以使用以下表达式:

myButton.place(x = 0, y = 0, width = 200, height = 30)

这样,按钮在其父对象中的位置
x=0,y=0

创建时,其大小为
200x30 px
。您在问题中描述的代码与发布的代码不匹配(其中大部分与所问问题无关)。请将此代码缩减为一个较小的值。例如,如果问题与小部件的大小有关,则不需要所有回调。@ScottHunter我已编辑了问题以删除不必要的代码。希望helps@DanyalDurrani请阅读布赖恩发布的链接。它会告诉你问题的代码部分应该发布什么。你删除了太多代码。您提供的示例需要最小化,但也要完整。“这是我所知道的确保按钮大小(以像素为单位)的唯一方法。”-有很多方法。Frame+pack_传播(0),或使用
place
,或在画布上创建图像对象,或者您可以给按钮一个不可见的1x1像素图像,使宽度和高度被解释为像素。@BryanOakley正如我所说的,这是我知道的唯一方法。。。我不确定是否还有其他选择。有几种方法可以计算像素大小,但帧是我唯一熟悉的方法。我更新了我的答案,以便更清楚地知道可能还有其他选项。因此PhotoImage可以创建一个没有引用的图像?@SierraMountainTech:是的。我必须添加选项
padx=0,pady=0
,以便在文本不为“”时获得一个方形按钮.在画布小部件中使用.place是迄今为止实现有保证的尺寸的最佳方法--谢谢!
myButton.place(x = 0, y = 0, width = 200, height = 30)