wxPython: 在子面板中更新图片位图

问题描述 投票:0回答:1

我是一个python和编程的初学者,试图实现一个基本的图像查看器,但在更新子面板时遇到了问题,图像应该显示在子面板中。当我在程序开始时向面板输入图像时,它能正确显示。然而,当我试图通过打开文件或打开目录-对话框用另一个图像更新面板时,它不能正确显示(见 截图).

从我目前所读到的关于更新面板的内容来看(按键刷新窗口的wxpython,wxPython - 通过按钮改变面板。,如何强制刷新一个wx.Panel?)只调用负责创建子面板的函数是不够的,但我似乎忽略了一些基本的东西,因为我无法在我的代码中得到任何建议的解决方案。

我也看了一下这个 相片浏览器教程 在鼠标与Python上,但我无法让它在我的程序中工作。

下面是我目前的代码。它也重现了你可以看到的错误结果。截图. 我很感激你能给我任何建设性的帮助和反馈。

import glob
import wx
import os

#====================================================================
class textEditor(wx.Panel):
    #----------------------------------------------------------------------
    def __init__(self, parent):

        wx.Panel.__init__(self, parent)

        sizer = wx.BoxSizer(wx.VERTICAL)

        speeBubImg = wx.StaticBox(self, wx.ID_ANY, "Text Editor")
        sizer.Add(speeBubImg, wx.ID_ANY, flag=wx.EXPAND|wx.ALL)

        self.SetSizer(sizer)

#====================================================================
class comicPagePanel(wx.Panel):
    #----------------------------------------------------------------------
    def __init__(self, parent, imgsPath):

        wx.Panel.__init__(self, parent)

#        print('comicPagePanel', imgsPath)

        # create the static box with the panel description...
        comPageStatBox = wx.StaticBox(self, wx.ID_ANY, "Comic Page")
        # ...and asign a sizer to it
        comPageStatBoxSizer = wx.StaticBoxSizer(comPageStatBox, wx.VERTICAL)

         # Feeding the panel with an image when starting the program works
#        imgsPath.append('someImage.jpg')

        if imgsPath:

#            print('comicPagePanel_if-imgPath', imgsPath)

            # create the image box
            comPageBox = wx.Bitmap(wx.Image(imgsPath[0], wx.BITMAP_TYPE_ANY))

            img = comPageBox.ConvertToImage()

            iW = img.GetWidth()
            iH = img.GetHeight()
            imgMaxSize = 1000

            if iW > iH:
                NewW = imgMaxSize
                NewH = imgMaxSize * iH / iW
            else:
                NewH = imgMaxSize
                NewW = imgMaxSize * iW / iH

            img = wx.Bitmap(img.Scale(NewW,NewH))

            # create another sizer for the actual image box
            comPageBoxSizer = wx.StaticBitmap(self, wx.ID_ANY, img)

            # add the image box sizer to the sizer of the
            # static box with the panel description
            comPageStatBoxSizer.Add(comPageBoxSizer, wx.ID_ANY, wx.EXPAND|wx.ALL)

        # create a main sizer which stretches all other sizers to the
        # size of the subpanel
        main_sizer = wx.BoxSizer()

        # add the static box with the image box that is nested in it
        # to the main sizer
        main_sizer.Add(comPageStatBoxSizer, wx.ID_ANY, wx.EXPAND|wx.ALL)

        # fit the main sizer to the subpanel
        self.SetSizer(main_sizer)

#====================================================================
class comicPageViewer(wx.Panel):
    #----------------------------------------------------------------------
    def __init__(self, parent, imgsPath):

        wx.Panel.__init__(self, parent)

        # laying out the grid for the image panel and the ctrl-buttons
        sizer = wx.GridBagSizer(2, 4)

        # the image viewing panel
        comPage = comicPagePanel(self, imgsPath)
        sizer.Add(comPage, pos=(0, 0), span=(1, 4),
                  flag=wx.EXPAND|wx.ALL, border=5)

        # the ctrl-buttons
        butPrev = wx.Button(self, label="Previous Page")
        butNext = wx.Button(self, label="Next Page")
        butOCR = wx.Button(self, label="Find Text/OCR")
        butSaveTxt = wx.Button(self, label="Save Current Text(s)")


        sizer.Add(butPrev, pos=(1, 0), flag=wx.EXPAND)
        sizer.Add(butNext, pos=(1, 1), flag=wx.EXPAND)
        sizer.Add(butOCR, pos=(1, 2), flag=wx.EXPAND)
        sizer.Add(butSaveTxt, pos=(1, 3), flag=wx.EXPAND)


        sizer.AddGrowableCol(0)
        sizer.AddGrowableCol(1)
        sizer.AddGrowableCol(2)
        sizer.AddGrowableCol(3)

        sizer.AddGrowableRow(0)

        self.SetSizer(sizer)

#====================================================================
class mainPanel(wx.Panel):
    #----------------------------------------------------------------------
    def __init__(self, parent, imgsPath):

        wx.Panel.__init__(self, parent)

#        print(imgsPath)

        # Create a sub panel left and right
        lSubPan = comicPageViewer(self, imgsPath)
        rSubPan = textEditor(self)

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(lSubPan, wx.ID_ANY, wx.EXPAND|wx.ALL)
        sizer.Add(rSubPan, wx.ID_ANY, wx.EXPAND|wx.ALL)
        self.SetSizer(sizer)

#====================================================================
class mainFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.createPanel()
        self.Maximize(True)
        self.Show()

    #----------------------------------------------------------  
    def createPanel(self):

        imgsPath = []

        self.CreateStatusBar()
        self.createMenu()
        panel = mainPanel(self, imgsPath)
    #----------------------------------------------------------
    def createMenu(self):      

        # create the menu bar
        menuBar = wx.MenuBar()

        # create a file menu
        fileMenu = wx.Menu()

        opFileBut = wx.MenuItem(fileMenu, wx.ID_ANY, '&Open File', 'Open a Single File')
        fileMenu.Append(opFileBut)

        # bind the open button to the on_open_directory event
        fileMenu.Bind(wx.EVT_MENU, self.onOpenFile, opFileBut)

        # add an open directory Button to the file menu
        opDirBut = wx.MenuItem(fileMenu, wx.ID_ANY, 'Open &Directory', 'Open Working Directory')
        fileMenu.Append(opDirBut)

        # bind the open button to the on_open_directory event
        fileMenu.Bind(wx.EVT_MENU, self.onOpenDirectory, opDirBut)

        # add a line separator to the file menu
        fileMenu.AppendSeparator()

        # add a quit button to fileMenu
        quitBut = wx.MenuItem(fileMenu, wx.ID_EXIT, '&Quit', 'Exit the Programm')
        fileMenu.Append(quitBut)

        # connect the quit button to the actual event of quitting the app
        fileMenu.Bind(wx.EVT_MENU, self.onQuit, quitBut)

        # call onQuit if the app is closed via x in title bar (in order to do some cleaning up)
        self.Bind(wx.EVT_CLOSE, self.onQuit)

        # give the menu a title
        menuBar.Append(fileMenu, "&File(s)")

        # connect the menu bar to the frame        
        self.SetMenuBar(menuBar)

    #----------------------------------------------------------
    def onOpenFile(self, event):

        with wx.FileDialog(self, "Choose a File",
                          style=wx.FD_DEFAULT_STYLE) as fDlg:
            if fDlg.ShowModal() == wx.ID_OK:

                imgPath = glob.glob(os.path.join(fDlg.GetPath()))

            if imgPath:
                comicPagePanel(self, imgPath)

    #----------------------------------------------------------
    def onOpenDirectory(self, event):

        with wx.DirDialog(self, "Choose a Directory",
                          style=wx.DD_DEFAULT_STYLE) as dDlg:
            if dDlg.ShowModal() == wx.ID_OK:

                imgsPath = glob.glob(os.path.join(dDlg.GetPath(), '*.jpg'))

            if imgsPath:
                comicPagePanel(self, imgsPath)

    #----------------------------------------------------------
    def onQuit(self, event):
        # get the frame's top level parent and close it
        wx.GetTopLevelParent(self).Destroy()


#======================
# Start GUI
#======================

if __name__ == '__main__':
    app = wx.App()
    mainFrame(None, title="Text from Comic Pages")
    app.MainLoop()
python bitmap wxpython panel
1个回答
0
投票

首先,任何时候wxpython把一些东西放在左上角都意味着它不知道该把它放在哪里,我想你已经解决了这个问题,但知道这个问题是有用的。这确实意味着你的wxpython对象存在并且可以被渲染,这至少是个问题。

第二次不能工作的原因是这段代码.comicPagePanel.com是由一个新的comicPagePanel.com创建的。

def onOpenFile(self, event):

    with wx.FileDialog(self, "Choose a File",
                      style=wx.FD_DEFAULT_STYLE) as fDlg:
        if fDlg.ShowModal() == wx.ID_OK:

            imgPath = glob.glob(os.path.join(fDlg.GetPath()))

        if imgPath:
            comicPagePanel(self, imgPath)

创建了一个新的comicPagePanel对象(在最后一行),但它是一个新的对象,与已经创建的对象完全分开。新的对象与任何sizer无关,它只是框架的一个子对象。所以它出现在左上角,因为没有任何布局与之相关。

你的代码在结构上不能达到你的要求。为了更新sizer中的图片,你需要得到这个对象。

comPageBoxSizer = wx.StaticBitmap(self, wx.ID_ANY, img)

并对其进行如下操作

comPageBoxSizer.SetBitmap( ... new bitmap object here ... )

注意,你也应该改变这个变量的名称。它不是一个sizer,它是一个StaticBitmap。你可以通过询问python它的类型来检查这个问题。

print(type(comPageBoxSizer))

在名称中加入类型是很合理的,而且也是很有帮助的,但是如果类型是错误的,那就完全没有帮助了。

一个有效的解决方案是在你的comicPagePanel类中有一个新的方法,它有一个新图片的参数,然后更新嵌入布局结构中的位图。

我希望从这段描述中你能明白为什么在运行开始时声明图片就能成功。图像被适当地放置在布局结构中。如果你后来添加了它,它就会与该布局完全分离。


0
投票

首先,再次感谢 鹰嘴兽 为我指出了正确的方向。我想出了一个可行的解决方案,但我不知道它是否是 "好 "代码。我只是简单地将图像定义为一个静态的类属性,它可以通过同一类中的附加 updateImage() 方法来改变。面板类comicPagePanel()的代码现在看起来是这样的。

#====================================================================
# the upper left panel that shows the image of the comic page
class comicPagePanel(wx.Panel):

    # create an "empty" image as placeholder;
    # it will be replaced by an actual image via the open file dialog
    comPageImg = wx.Image(1,1)

    #----------------------------------------------------------------------
    def __init__(self, parent):
        # Constructor
        wx.Panel.__init__(self, parent)

        # create the static box with the panel description...
        comPageStatBox = wx.StaticBox(self, wx.ID_ANY, "Comic Page")
        # ...and asign a sizer to it
        comPageStatBoxSizer = wx.StaticBoxSizer(comPageStatBox, wx.VERTICAL)

        # get the background color of the panel
        [panR, panG, panB] = self.GetBackgroundColour()[:3]

        # set the color of the image placeholder to the background color of the panel
        comicPagePanel.comPageImg.Replace(0,0,0,panR,panG,panB)

        # convert the image placeholder to a static bitmap
        comicPagePanel.comPageImg = wx.StaticBitmap(self, wx.ID_ANY, wx.Bitmap(comicPagePanel.comPageImg))

        # add the image placeholder to the sizer of the
        # static box with the panel description; meaning, placing it within the static box
        comPageStatBoxSizer.Add(comicPagePanel.comPageImg, wx.ID_ANY, wx.EXPAND|wx.ALL)

        # create a main sizer which stretches all other sizers to the
        # size of the subpanel
        main_sizer = wx.BoxSizer()

        # add the static box with the image that is nested in it
        # to the main sizer
        main_sizer.Add(comPageStatBoxSizer, wx.ID_ANY, wx.EXPAND|wx.ALL)

        # fit the main sizer to the subpanel
        self.SetSizer(main_sizer)

    #----------------------------------------------------------------------
    # the update method of the comic page image viewer
    def updateImage(self, imgsPath):

        # get the new image
        newImg = wx.Image(imgsPath[0], wx.BITMAP_TYPE_ANY)

        # get the display resolution in order to fit the image into the panel
        [disX, disY] = wx.GetDisplaySize()

        # determine the approximate size of the image panel
        disX = disX/2-50
        disY = disY-175

        # get the size of the new image
        [iW, iH] = newImg.GetSize()

        # scale the image proportionally        
        if not iH < disY and iW > iH:
            NewW = disX
            NewH = disX * iH / iW
            # scaling the page image
            newImg = newImg.Scale(NewW,NewH)
        elif not iW < disX:
            NewH = disY
            NewW = disY * iW / iH
            # scaling the page image
            newImg = newImg.Scale(NewW,NewH)

        # replace the old image in the panel with the new one
        comicPagePanel.comPageImg.SetBitmap(wx.Bitmap(newImg))

现在,如果用户想通过文件对话框打开一张新图片, updateImage() 方法就会被调用。这个调用看起来像这样。

#----------------------------------------------------------
# open a file dialog
def onOpenFile(self, event):

    with wx.FileDialog(self, "Choose a File",
                      style=wx.FD_DEFAULT_STYLE) as fDlg:
        if fDlg.ShowModal() == wx.ID_OK:

            imgPath = glob.glob(os.path.join(fDlg.GetPath()))

        if imgPath:
            comicPagePanel.updateImage(self, imgPath)
        else:
            return
© www.soinside.com 2019 - 2024. All rights reserved.