Forum: wxRuby Question on using images on panels

Posted by Alpha Blue (elricstorm)
on 2010-01-22 18:36
I'm trying to place a simple logo on one of the panels within the center
of my main gui.  In DialogBlocks, the panel class is LogoPanel which
when using xrcise to generate the ruby file from xrc, creates:

@logo = finder.call("logo")
@logo.extend(LogoPanel)

In my main loop I have:

class GuiMain < XrcFrameMain
  def initialize
    super()
    evt_menu( @mb_fm_new, :on_new_workspace )
    evt_menu( @mb_fm_save, :on_save_workspace )
    evt_menu( @mb_fm_exit, :on_exit )
    st_response("Idle...",2)
    st_response(Time.now.strftime("%B %d, %Y"), 1)
  end
end

module LogoPanel
  # logo image
  img_file = File.join( File.dirname(__FILE__)+"/../images/kirin",
    'logo.png')
  @bitmap = Wx::Bitmap.new(img_file, Wx::BITMAP_TYPE_PNG)
  self.paint do |dc|
    dc.draw_line(@bitmap, @offset, @offset, false)
  end
end

which generates the following error:

E:\Gui-Development\Kirin>ruby start
E:/Gui-Development/Kirin/lib/main.rb:25:in `<module:LogoPanel>':
undefined metho
d `paint' for LogoPanel:Module (NoMethodError)
        from E:/Gui-Development/Kirin/lib/main.rb:20:in `<top
(required)>'
        from start:12:in `load'
        from start:12:in `<main>'

I can't make the LogoPanel a class because I will receive an error that
it was expecting a module to be there.  So, I believe the class for this
particular panel expects a module class.  Without this code in there, or
just using:

module LogoPanel
end

.. the gui will show but the section where the logo should appear is all
white as it is missing the paint.

This is a rather important topic for me because I'd like to understand
better how to paint and change the appearance of my GUI in many areas...

For instance, I want to add a custom png file as the background of my
entire GUI and then paint the logo on the side, etc.  This app will be
used cross platform so the images will have to be converted to a usable
source, which I haven't gotten into yet.

Any ideas on everything I just posted?

Thanks.
Posted by Mario Steele (Guest)
on 2010-01-22 21:37
(Received via mailing list)
Hello Alpha,

On Fri, Jan 22, 2010 at 12:36 PM, Alpha Blue <lists@ruby-forum.com> 
wrote:

>  def initialize
>  # logo image
>  img_file = File.join( File.dirname(__FILE__)+"/../images/kirin",
>    'logo.png')
>  @bitmap = Wx::Bitmap.new(img_file, Wx::BITMAP_TYPE_PNG)
>  self.paint do |dc|
>    dc.draw_line(@bitmap, @offset, @offset, false)
>  end
> end
>
>
This part is where you have the problem, your doing the call to 
self.paint
in the top level of the module, which self is the Module Class, and in 
which
does not have a paint method associated with the module itself.  Even 
after
you extend your object to include the Module, this code still is 
expecting
self to be the Module, not the class instance that your extending.
 Therefore, your problem lies with this.

The solution to this, is to do the following with your module:

module LogoPanel
  def setup_resources
    img_file =
File.join(File.dirname(__FILE__),"..","images","kirin","logo.png")
    @bitmap = Wx::Bitmap.new(img_file, Wx::BITMAP_TYPE_ANY)
    self.evt_paint do |event|
      self.paint do |dc|
        dc.draw_bitmap(@bitmap,0,0,false)
      end
    end
  end
end

Then just after your @logo.extend(LogoPanel), you just type
@logo.setup_resources()

Now, you'll notice two things different in my version, compared to 
yours, as
far as setting things up, I put everything into a Method that you will 
need
to invoke, in order to get your Bitmap to use for drawing, and in the 
method
in which I get the filename.  With File.join(), it has a variable 
argument
passing setup to the signature for it, so you can pass as many 
parameters to
it that you want, and it will build up the path, with the operating 
system
slash in use.  This is the optimal method in which to build paths, as 
it's
never a guarantee that the '/' slash character will work.  File.join() 
will
automatically use the correct path separator for you.

Lastly, I used draw_bitmap, instead of draw_line, as this is just the 
most
simplest way in which to do this, when not using a Wx::StaticBitmap, to
display the Image, which is another option, instead of you drawing it
yourself, as WxWidgets and wxRuby will handle the drawing of the bitmap 
for
you.

which generates the following error:
> I can't make the LogoPanel a class because I will receive an error that
> This is a rather important topic for me because I'd like to understand
> better how to paint and change the appearance of my GUI in many areas...
>
> For instance, I want to add a custom png file as the background of my
> entire GUI and then paint the logo on the side, etc.  This app will be
> used cross platform so the images will have to be converted to a usable
> source, which I haven't gotten into yet.
>

As for this, if you want to use a custom png for the background of your
entire GUI, the best suggestion to use, is the evt_erase_background 
method
for catching background erases, and drawing custom images for the 
background
of your application.  In this method, you need to do the following:

self.evt_erase_background do |event|
  self.paint do |dc|
    dc.draw_bitmap(@bitmap,0,0,false)
  end
end

hth,

Mario
Posted by Alpha Blue (elricstorm)
on 2010-01-22 22:32
Hi Mario,

I'm losing hair and you just saved me from pulling out the rest of it. 
My thanks!

I actually understood everything you said and fixed it in a matter of 30 
seconds.  Once I saw how you extended the module, I felt a little silly. 
But, that's okay since I'm a novice designer in ruby. :)

Here's what I did and why I did it with changes from you:

My new module is:

module LogoPanel
  def setup_resources
    img_file = 
File.join(File.dirname(__FILE__),"..","images","kirin","logo.png")
    @bitmap = Wx::Bitmap.new(img_file, Wx::BITMAP_TYPE_ANY)
    self.evt_paint do |event|
      self.paint do |dc|
        dc.draw_bitmap(@bitmap,0,0,false)
      end
    end
  end
end

And I actually accessed it in initializers like such:

class GuiMain < XrcFrameMain
  def initialize
    super()

    # File Menu - new workspace
    evt_menu( @mb_fm_new, :on_new_workspace )
    # File Menu - save workspace
    evt_menu( @mb_fm_save, :on_save_workspace )
    # File Menu - exit
    evt_menu( @mb_fm_exit, :on_exit )
    # Status Bar text (3 frames so 0,1,2 are relevant array positions)
    st_response("Idle...",2)
    st_response(Time.now.strftime("%B %d, %Y"), 1)

    # setup the logo here
    @logo.setup_resources()

  end
end

I didn't want to put the @logo.setup_resources() after the code in the 
ruby file that's being translated from XRC because it states not to 
change any of the file but to instead extend upon the file.

My biggest issue has been trying to understand how to tie in modules and 
other classes and where to place the code.  You've helped me out a bunch 
with regards to this.  I plan on changing my initializers so that the 
events are all stored in a method like:

def register_event_handler
  evt_menu( @mb_fm_new, :on_new_workspace )
  evt_menu( @mb_fm_save, :on_save_workspace )
  evt_menu( @mb_fm_exit, :on_exit )
end

and then the initializers file can look like such:

class GuiMain < XrcFrameMain
  def initialize
    super()

    # Status Bar text (3 frames so 0,1,2 are relevant array positions)
    st_response("Idle...",2)
    st_response(Time.now.strftime("%B %d, %Y"), 1)

    # setup the logo here
    @logo.setup_resources()

    # process events
    register_event_handler

  end
end

I can do the same for objects that I need to have painted.

But, I'm unsure about how to go about painting the main gui.  I see your 
code but I'm not sure I understand it.  Is it going into my 
initializers?

self.evt_erase_background do |event|
  self.paint do |dc|
    dc.draw_bitmap(@bitmap,0,0,false)
  end
end

and then supply a bitmap for it like I did with the logo?  If so, then I 
understand what you are trying to tell me and I thank you once again.

My largest issue was finding very little documentation on how to use 
both WxRuby and DialogBlocks together simultaneously.  I've been 
figuring it all out as I go and the one tutorial I did fine was very 
basic and trivial.  So, it didn't help me out as much as it could have.

Thank you.
Posted by Alpha Blue (elricstorm)
on 2010-01-22 22:43
Hi Mario,

It's all working now.  Here's the touched up code:

http://gist.github.com/284158

I'm able to color the background of the main gui and place the logo in. 
There's only one issue and that is I notice I see a border on the logo. 
My guess is it's due to a border I might have set in dialogblocks so 
I'll troubleshoot from there.

thanks again.
Posted by Alpha Blue (elricstorm)
on 2010-01-22 22:58
Okay one last follow-up.  Here's what it's looking like with the code. 
Keep in mind that these two images are just examples and not what I'll 
actually use in my GUI.

http://i780.photobucket.com/albums/yy89/jdezenzio/kirin_tear.jpg

The two problems I see are:

The Kirin logo to the top left just below the toolbar has a tiny bit of 
gray space just above the top of it.  In addition, it has some strange 
white border around the image.  I checked dialogblocks and removed all 
of the borders, setting them to 0 and unclicked them but they still 
appear.

Secondly, when the image is sized there's tearing across the platform.

Lastly, I'm not sure how to use just a small one pixel png image and 
stretch it as the entire background of my program using this code.

Thoughts?

Many thanks.
Posted by Alpha Blue (elricstorm)
on 2010-01-23 18:07
My fix for this was the following:

1.  Until I can figure out how to make a small static image (say 1px x 
10px) stretch and fill the entire window of my gui on user resize, and 
have it paint correctly, I ended up forcing a no-resize option on the 
gui and created a static image using the suggestions posted above.

2.  The small gap between the picture was borders that were set on the 
sizers themselves with dialogblocks.  On almost all elements that 
dialogblocks places on the screen, they all seem to start out with a 5 
width top,right,left,bottom border.  So, if anyone encounters something 
similar, make sure to remove all the borders.  The same thing happens 
when you insert spacers.

So, this particular issue is closed unless someone can guide me with a 
step-by-step process on how to set a small .png as a scaled background 
on resize events.

Thanks.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.