Hi guys,
I’m working in a project which requires very basic image processing. Due to pandemic, all classes in my university are online only. This project is for an engineering class that teaches how water systems works. Students should manipulate water bombs, read data from screens, open / close pumps, etc.
So, there will be a image and transparent buttons (or things that can behaive like a button) on top of very specific spots on the image. The buttons will be over the instruments where the user can interact with. The interactions and such I can do with no problem.
What I have now is a very basic image viewer software. There is a eye button on the toolbar that shows a right sizer which I will show relevant information based on what button was clicked. What I need now is way to save the position of a button and to keep it consistent to the image when the sizer the image is in gets resized.
As for the saving of the initial coordinate, I can dump to a .json file, but I don’t know the math and how to set the buttons on top of the image. The code below I made it copying here and there.
Icons and image below:
import wx, os
class MainFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent)
self.bInfoSizerVisibility = False
self.images = []
self.index = 0
self.toolbar = self.CreateToolBar()
self.initToolbar()
self.initUI()
self.CenterOnScreen()
self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
self.Bind(wx.EVT_SIZE, self.OnResizing)
def initToolbar(self):
''' Initialize the toolbar. '''
left_arrow = self.toolbar.AddTool(wx.ID_ANY, 'Left', wx.Bitmap('images/icons/left.png'))
right_arrow = self.toolbar.AddTool(wx.ID_ANY, 'Right', wx.Bitmap('images/icons/right.png'))
show_icon = self.toolbar.AddTool(wx.ID_ANY, 'See / Unsee', wx.Bitmap('images/icons/eye.png'))
self.Bind(wx.EVT_TOOL, self.OnNext, right_arrow)
self.Bind(wx.EVT_TOOL, self.OnPrevious, left_arrow)
self.Bind(wx.EVT_TOOL, self.OnInfoSizer, show_icon)
self.toolbar.Realize()
def initUI(self):
''' Initialize the UI. '''
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
self.imageSizer = wx.BoxSizer(wx.VERTICAL)
self.imageSizer.SetMinSize((800, 600))
self.infoSizer = wx.BoxSizer(wx.VERTICAL)
self.infoSizer.Add( wx.StaticText(self, -1, 'Placeholder Text') )
self.infoSizer.ShowItems(self.bInfoSizerVisibility)
self.bitmap = None
self.image = None
self.aspect = None
self.bmpImage = wx.StaticBitmap(self, wx.ID_ANY)
self.imageSizer.Add(self.bmpImage, 1, wx.EXPAND, 0)
mainSizer.Add(self.imageSizer, 1, wx.EXPAND, 0)
mainSizer.Add(self.infoSizer)
self.images = self.getFolderImages('images/system1')
self.SetSizerAndFit(mainSizer)
self.frameImage(self.images[self.index])
self.Layout()
def frameImage(self, path, isJustResize=False):
''' Recivies the path and updates the image on the screen. '''
if not isJustResize:
self.bitmap = wx.Bitmap(path, wx.BITMAP_TYPE_ANY)
self.image = wx.Bitmap.ConvertToImage(self.bitmap)
self.aspect = self.image.GetSize()[1] / self.image.GetSize()[0]
self.Layout() # To update the size of self.imageSizer
sW, sH = self.imageSizer.GetSize()
newW = sW
newH = int(newW * self.aspect)
if newH > sH:
newH = sH
newW = int(newH / self.aspect)
image = self.image.Scale(newW, newH)
self.bmpImage.SetBitmap(image.ConvertToBitmap())
self.Layout()
print(f"Image New Size: ({newW}, {newH})")
print(f"App Size: {self.GetSize()}")
print(f"imageSizer Size: {self.imageSizer.GetSize()}\n")
def getFolderImages(self, path):
''' Recivies the path of a given folder and returns a list with the images paths. '''
jpgs = [f for f in os.listdir(path) if f[-4:] == ".jpg"]
return [os.path.join(path, f) for f in jpgs]
def OnNext(self, event):
self.index += 1
if self.index >= len(self.images):
self.index = 0
self.frameImage(self.images[self.index])
def OnPrevious(self, event):
self.index -= 1
if self.index < 0:
self.index = len(self.images) - 1
self.frameImage(self.images[self.index])
def OnKey(self, event):
if event.GetKeyCode() == wx.WXK_LEFT:
self.OnPrevious(None)
if event.GetKeyCode() == wx.WXK_RIGHT:
self.OnNext(None)
def OnResizing(self, event):
self.frameImage(self.images[self.index], True)
event.Skip()
def OnInfoSizer(self, event):
''' Shows / hides the infoSizer panel. Will contain more complicated widgets in the future. '''
value = self.bInfoSizerVisibility
self.infoSizer.ShowItems(not value)
self.bInfoSizerVisibility = not value
self.Layout()
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
Thank you very much!