如何修复Kivy应用中的重复错误?

时间:2019-10-30 19:49:20

标签: python python-3.x kivy kivy-language

我使用python和Kivy进行了简单的游戏。有一天,当我运行代码时,出现了重复图形问题。基本上,屏幕上的每个对象都会出现多次(就像其一遍又一遍地绘制屏幕上的所有对象一样)。该程序曾经可以正常运行,但是有一天这个问题才刚刚开始发生。

我已经尝试在朋友计算机上运行相同的代码,并且效果很好,因此可能与硬件有关。 (我有Alienware 17 r4,他有Macbook)没有问题的以前版本的代码现在都拥有它。

编辑:我认为问题与透明画布无法正常运行有关。我发现了一个我认为可以描述相同问题的问题:

Kivy canvas.clear() not clearing the canvas

但是这个问题没有得到回答。如我所链接的问题所述,手动调整屏幕大小可使问题消失

import kivy
from kivy.app import App
from kivy.core.text import Label as CoreLabel
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.graphics import *
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.core.window import Window
kivy.require('1.0.6')  # replace with your current kivy version !

class ConnectApp(App):

    def build(self):
        return kv_file

class Menu(Screen):
    pass

class Setting(Screen):
    pass

class Main(Screen):
    board = [
        [2, 2, 2],
        [0, 0, 0],
        [1, 1, 1]
    ]
    hold_piece: bool = False
    temp = 0
    move_no = 0

    P1win = False
    P2win = False

    def __init__(self, **kwargs):
        super(Main, self).__init__(**kwargs)
        self.bind(pos=self.update_canvas)
        self.bind(size=self.update_canvas)
        self.update_canvas()

    def update_canvas(self, *args):
        self.canvas.clear()
        with self.canvas:
            get_indexes = lambda x, xs: [i for (y, i) in zip(xs, range(len(xs))) if x == y]
            for i in self.board:
                for index in get_indexes(1, i):
                    Color(1, 0, 0, 1)
                    Ellipse(pos=(self.size[0] * index * 0.25, self.size[1] * self.board.index(i) * 0.25 + self.size[1]*0.125),
                            size=(self.size[0] * 0.25, self.size[1] * 0.25))
                for index in get_indexes(2, i):
                    Color(0, 0, 1, 1)
                    Ellipse(pos=(self.size[0] * index * 0.25, self.size[1] * self.board.index(i) * 0.25 + self.size[1]*0.125),
                            size=(self.size[0] * 0.25, self.size[1] * 0.25))
            mylabel = CoreLabel(text="Reset", font_size=25, color=(1, 1, 1, 1))
            mylabel.refresh()
            texture = mylabel.texture
            Color(1, 1, 1, 1)
            Rectangle(pos=(self.size[0] * 0.8, self.size[1] * 0.65), size=(self.size[0] * 0.15, self.size[1] * 0.15), texture=texture)
            label2 = CoreLabel(text="Menu", font_size=25, color=(1, 1, 1, 1))
            label2.refresh()
            texture = label2.texture
            Color(1, 1, 1, 1)
            Rectangle(pos=(self.size[0] * 0.8, self.size[1] * 0.25), size=(self.size[0] * 0.15, self.size[1] * 0.15), texture=texture)

    def press(self, row, col):
        if self.move_no % 2 == 0:
            if self.board[row][col] == 2 and not self.hold_piece:
                self.temp = self.board[row][col]
                self.board[row][col] = 0
                self.hold_piece = True
            elif self.board[row][col] == 0 and self.hold_piece:
                self.board[row][col] = self.temp
                self.temp = 0
                self.hold_piece = False
                self.update_canvas()
                self.move_no += 1
            else:
                pass
        else:
            if self.board[row][col] == 1 and not self.hold_piece:
                self.temp = self.board[row][col]
                self.board[row][col] = 0
                self.hold_piece = True
            elif self.board[row][col] == 0 and self.hold_piece:
                self.board[row][col] = self.temp
                self.temp = 0
                self.hold_piece = False
                self.update_canvas()
                self.move_no += 1
                self.checkWin()
                self.wincon()
            else:
                pass

    def reset(self):

        self.board = [
        [2, 2, 2],
        [0, 0, 0],
        [1, 1, 1]]

        self.move_no = 0
        self.update_canvas()

    def checkWin(self):

        if self.board[0][0] == self.board[1][0] == self.board[2][0] == 1 or self.board[0][1] == self.board[1][1] == self.board[2][1] == 1 or self.board[0][2] == self.board[1][2] == self.board[2][2] == 1:
            self.P1win = True
        elif self.board[0][0] == self.board[0][1] == self.board[0][2] == 1 or self.board[1][0] == self.board[1][1] == self.board[1][2] == 1:
            self.P1win = True
        elif self.board[0][0] == self.board[1][1] == self.board[2][2] == 1 or self.board[0][2] == self.board[1][1] == self.board[2][0] == 1:
            self.P1win = True
        elif self.board[0][0] == self.board[1][0] == self.board[2][0] == 2 or self.board[0][1] == self.board[1][1] == self.board[2][1] == 2 or self.board[0][2] == self.board[1][2] == self.board[2][2] == 2:
            self.P2win = True
        elif self.board[2][0] == self.board[2][1] == self.board[2][2] == 2 or self.board[1][0] == self.board[1][1] == self.board[1][2] == 2:
            self.P2win = True
        elif self.board[0][0] == self.board[1][1] == self.board[2][2] == 2 or self.board[0][2] == self.board[1][1] == self.board[2][0] == 2:
            self.P2win = True
        else:
            pass

    def wincon(self):
        if self.P1win:
            print("Player 2 wins")
            pop(2)
        elif self.P2win:
            print("Player 1 wins")
            pop(1)
        else:
            pass

class p1_win():
    pass

class p2_win():
    pass

def pop(num):
    if num == 1:
        show = p1_win()
        popup = Popup(content=show, size_hint=(None, None), size =(400, 400))
    else:
        show = p2_win()
        popup = Popup(content=show, size_hint=(None, None), size=(400, 400))

    popup.open()

class WinManager(ScreenManager):
    pass


kv_file = Builder.load_string("""
WinManager:
    Menu:
    Main:
    Setting:

<Menu>:
    name: "menu"
    FloatLayout:
        Label:
            size_hint: 0.5, 0.25
            pos_hint: {"x": 0.25, "y": 0.7}
            text: "Connect 3"
            font_size: 40
            background_color: 1, 1, 1, 1
        Button:
            text: "Play"
            background_color: 0.4,1,0.4 ,1
            size_hint: 0.34, 0.16
            pos_hint: {"x":0.33, "y":0.3}
            on_press: root.manager.current = "main"
        Button:
            text: "Settings"
            background_color: 0.4, 1, 0.4, 1
            size_hint: 0.34, 0.16
            pos_hint: {"x":0.33, "y":0.1}
            on_press: root.manager.current = "setting"


<Main>:
    name: "main"
    FloatLayout:
        size: root.width, root.height

        Button:
            pos_hint:{"x":0.8 , "y":0.65}
            on_press: root.reset()
            size_hint: 0.15, 0.15

        Button:
            pos_hint:{"x":0.8 , "y":0.25}
            on_press:
                root.manager.transition.direction = 'right'
                root.manager.current = "menu"
            size_hint: 0.15, 0.15

        Button:
            pos_hint:{"x":0 , "y":0.125}
            text: "A1"
            on_press: root.press(0, 0)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0 , "y":0.375}
            text: "A2"
            on_press: root.press(1, 0)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0 , "y":0.625}
            text: "A3"
            on_press: root.press(2, 0)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0.25 , "y":0.125}
            text: "B1"
            on_press: root.press(0, 1)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0.25 , "y":0.375}
            text: "B2"
            on_press: root.press(1, 1)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0.25 , "y":0.625}
            text: "B3"
            on_press: root.press(2, 1)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0.5 , "y":0.125}
            text: "C1"
            on_press: root.press(0, 2)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0.5 , "y":0.375}
            text: "C2"
            on_press: root.press(1, 2)
            size_hint:0.25, 0.25
        Button:
            pos_hint:{"x":0.5 , "y":0.625}
            text: "C3"
            on_press: root.press(2, 2)
            size_hint:0.25, 0.25

<Setting>:
    name: "setting"
    Label:
        size_hint: 0.5, 0.25
        pos_hint: {"x": 0.25, "y": 0.7}
        text: "I'm not smart enough to add settings"
    Button:
        text: "Go Back"
        background_color: 0.4,1,0.4 ,1
        size_hint: 0.34, 0.16
        pos_hint: {"x":0.33, "y":0.1}
        on_press:
            root.manager.transition.direction = 'right'
            root.manager.current = "menu"
""")

if __name__ == '__main__':
    #Window.fullscreen = True
    ConnectApp().run()

如果有帮助,这是终端中的输出:

[INFO   ] [Logger      ] Record log in C:\Users\muham\.kivy\logs\kivy_19-10-30_4.txt
[INFO   ] [deps        ] Successfully imported "kivy_deps.gstreamer_dev" 0.1.17
[INFO   ] [deps        ] Successfully imported "kivy_deps.gstreamer" 0.1.17
[INFO   ] [deps        ] Successfully imported "kivy_deps.angle" 0.1.9
[INFO   ] [deps        ] Successfully imported "kivy_deps.glew" 0.1.12
[INFO   ] [deps        ] Successfully imported "kivy_deps.glew_dev" 0.1.12
[INFO   ] [deps        ] Successfully imported "kivy_deps.sdl2" 0.1.22
[INFO   ] [deps        ] Successfully imported "kivy_deps.sdl2_dev" 0.1.22
[INFO   ] [Kivy        ] v1.11.1
[INFO   ] [Kivy        ] Installed at "C:\Users\muham\PycharmProjects\Connect3\venv\lib\site-packages\kivy\__init__.py"
[INFO   ] [Python      ] v3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 22:20:52) [MSC v.1916 32 bit (Intel)]
[INFO   ] [Python      ] Interpreter at "C:\Users\muham\PycharmProjects\Connect3\venv\Scripts\python.exe"
[INFO   ] [Factory     ] 184 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2, img_gif (img_pil, img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2
[INFO   ] [Window      ] Provider: sdl2
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] GLEW initialization succeeded
[INFO   ] [GL          ] Backend used <glew>
[INFO   ] [GL          ] OpenGL version <b'4.6.0 - Build 26.20.100.6859'>
[INFO   ] [GL          ] OpenGL vendor <b'Intel'>
[INFO   ] [GL          ] OpenGL renderer <b'Intel(R) HD Graphics 630'>
[INFO   ] [GL          ] OpenGL parsed version: 4, 6
[INFO   ] [GL          ] Shading version <b'4.60 - Build 26.20.100.6859'>
[INFO   ] [GL          ] Texture max size <16384>
[INFO   ] [GL          ] Texture max units <32>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO   ] [GL          ] NPOT texture support is available
[INFO   ] [Base        ] Start application main loop
[INFO   ] [WindowSDL   ] exiting mainloop and closing.
[INFO   ] [Base        ] Leaving application in progress...

这是屏幕上显示的内容:

我运行代码时的屏幕截图

3 个答案:

答案 0 :(得分:0)

运行游戏时,我得到了三个屏幕

screen1

screen2

screen3

正如John Anderson所说,您需要查找kivy文件(.kv)才能找到诸如带有两种不同按钮的窗口之类的冲突。为什么?因为kivy运行代码并搜索文件的相同名称(.py),但扩展名为.kv。

有例外:如果类名以

结尾
class ExampleApp(Screen):

kivy正在呼叫

<Example>

请确认程序所在的文件夹中是否还有其他kivy文件。

如果错误仍然存​​在,请尝试安装其他版本的kivy

pip install --upgrade kivy

答案 1 :(得分:0)

我相信您看到的是图形系统无法正确处理SlideTransition中的WinManager。因此,过渡的所有动画步骤都保留在显示器上。您可以通过更改transition的{​​{1}}属性来避免这种情况。我会先尝试WinManager。在您的“ kv”中,将NoTransition规则更改为:

WinManager:

答案 2 :(得分:0)

尝试一下:

def zip_dir(src_dir, dst_zip, *, skip_suffixes=None, dry=False):
    import logging
    from pathlib import Path
    from os import walk
    from tempfile import TemporaryDirectory
    from zipfile import ZipFile, ZipInfo

    _log = logging.getLogger(zip_dir.__name__)
    _log.addHandler(logging.NullHandler())
    _sep = 50 * "-"

    skip_suffixes = skip_suffixes or []
    src_dir, dst_zip = Path(src_dir), Path(dst_zip)
    _log.info("zipping dir: '%s' to: '%s", str(src_dir), str(dst_zip))

    if not src_dir.exists():
        raise FileNotFoundError(str(src_dir))
    if not src_dir.is_dir():
        raise NotADirectoryError(str(src_dir))
    if dst_zip.exists():
        raise FileExistsError(str(dst_zip))

    with TemporaryDirectory() as tmp_dir:
        tmp_zip_path = Path(tmp_dir).joinpath(dst_zip.name)

        with ZipFile(str(tmp_zip_path), mode="w") as zip_out:
            for root, dirs, files in walk(src_dir):
                root = Path(root)

                for folder in dirs:
                    folder = root.joinpath(folder)

                    # add empty folders to the zip
                    if not list(folder.iterdir()):
                        _log.debug(_sep)
                        folder_name = f"{str(folder.relative_to(src_dir))}/"
                        _log.debug("empty dir: '%s'", folder_name)

                        if dry:
                            continue

                        zip_out.writestr(ZipInfo(folder_name), "")

                for file in files:
                    file = root.joinpath(file)
                    _log.debug(_sep)
                    _log.debug("adding:  '%s'", str(file))

                    should_skip = None
                    for suffix in file.suffixes:
                        if suffix in skip_suffixes:
                            should_skip = suffix
                            break

                    if should_skip:
                        _log.debug("skipped [%s]: %s", should_skip, str(file))
                        continue

                    arcname = str(file.relative_to(src_dir))
                    _log.debug("arcname: '%s'", arcname)

                    if dry:
                        continue

                    zip_out.write(str(file), arcname=arcname)

        if not dry:
            dst_zip.write_bytes(tmp_zip_path.read_bytes())

        tmp_zip_path.unlink()

if __name__ == '__main__':
    import logging
    logging.basicConfig(level=logging.DEBUG, format="%(asctime)s | %(levelname)8s | %(module)25s:%(lineno)-5s | %(message)s")

    zip_dir("/tmp/opera_profile", "opera_profile.zip", skip_suffixes=[".log"], dry=True)

Intel HD Graphics在OpenGL方面经常遇到很多麻烦。