I have written the program below. It displays an image within a hbox inside a scrolledwindow. The image moves forward when space key is pressed, backwards when backspace is pressed. Whenever an image is changed, I set the scrolledwindow adjustments value to 0.0 so that it will always display from the start. But this is not working correctly, for example when I use the mouse wheel to scroll the image up or down, press space or backspace, it will sometimes show the next/previous image from the top or stay at that position. I want it to always show the next/prev image from the top. Have I messed up somewhere? I'm using ruby-gtk 4.0.8.
require 'gtk3'
class Window < Gtk::ApplicationWindow
def initialize(app)
super(app)
set_default_size(800, 600)
path = File.expand_path('~/Manga/Deadman Wonderland')
#images = Dir.children(path).map { |file| "#{path}/#{file}" }
#sc_win = Gtk::ScrolledWindow.new
#box = Gtk::Box.new(:horizontal)
#box.halign = :center
#box.valign = :center
#image = Gtk::Image.new
#image_index = -1
signal_connect('key-press-event') do |_widg, event|
case event.keyval
when Gdk::Keyval::KEY_space
reset_viewport
next_image
when Gdk::Keyval::KEY_BackSpace
reset_viewport
prev_image
end
end
next_image
#box.add(#image)
#sc_win.add(#box)
add(#sc_win)
end
def next_image
if #image_index < #images.length - 1
#image.pixbuf.unref if #image.pixbuf
#image_index += 1
#image.set_pixbuf(GdkPixbuf::Pixbuf.new(:file => #images[#image_index]))
end
end
def prev_image
if #image_index > 0
#image.pixbuf.unref if #image.pixbuf
#image_index -= 1
#image.set_pixbuf(GdkPixbuf::Pixbuf.new(:file => #images[#image_index]))
end
end
def reset_viewport
#sc_win.hadjustment.set_value(0.0)
#sc_win.vadjustment.set_value(0.0)
end
end
app = Gtk::Application.new(nil, :flags_none)
app.signal_connect('activate') { Window.new(app).show_all }
app.run
I tried printing out the value of vertical adjustment whenever it changed. I noticed that at some point after calling reset_viewport, its value reset from 0.0 to the previous one.
#sc_win.vadjustment.signal_connect('value-changed') do
p #sc_win.vadjustment.value
end
494.0 #at bottom of image
0.0 #after pressing space key
494.0 #jumps back!
Related
I was trying to make a multiple-choice music player using Gosu but the picture and music Iwanted would not initialize despite the program running, it showed a black screen. The single block of codes works:
require 'gosu'
require './input_functions'
class MW < Gosu::Window
def initialize
super 200, 135
#beth = Gosu::Image.new("media/beth.jpg")
#song = Gosu::Song.new("media/3rdmovement.mp3")
#song.play
end
def draw
#beth.draw(0, 0)
end
end
window = MW.new
window.show
But adding the multiple choice elements would not work(note: read_integer_in_range is defined in input function, the name itself is self explanatory). Full code:
require 'gosu'
require './input_functions'
class MW < Gosu::Window
def initialize
super 200, 135
#beth = Gosu::Image.new("media/beth.jpg")
#dimitri = Gosu::Image.new("media/dimitri.png")
#vil = Gosu::Image.new("media/vilva.png")
#song = Gosu::Song.new("media/3rdmovement.mp3")
#song2=Gosu::Song.new("media/2ndwaltz.mp3")
#song3=Gosu::Song.new("media/1stseason.mp3")
read_integer_in_range( "What song you want play
1st Spring
2nd Waltz
3rd movement", 1, 3)
choice = gets.chomp.to_i()
case choice
when 1
#song3.play
#vil.draw(0, 0)
when 2
#song2.play
#dimitri.draw(0, 0)
when 3
#song.play
draw_beth()
end
end
end
def draw_beth
#beth.draw(0, 0)
end
window = MW.new
window.show
All of the Png/Jpg and mp3 file works just fine..
I tried separating the draw_beth to call it in case but it did not work. I hope some passing by could help me with this one
As I can see, you are creating a music player with GUI, and if you are doing so, you shouldn't use gets function, instead you should track for the cursor's position and return a test value; for example:
def update
#locs = [mouse_x, mouse_y]
#cursor_choice_album = mouse_over_button(mouse_x, mouse_y)
end
def needs_cursor?; true; end
def mouse_over_button(mouse_x, mouse_y)
if ((mouse_x > 100 and mouse_x < 500) and (mouse_y < 500 and mouse_y > 100))
return 1
end
then you can use the case condition in the "button down ID" function
I've been having trouble centering text in the Gosu library to the absolute middle of the screen.
require 'gosu'
class GameWindow < Gosu::Window
def initialize (width=800, height=600, fullscreen=false)
super
self.caption = 'Hello'
#message = Gosu::Image.from_text(
self, 'HELLO WORLD', Gosu.default_font_name, 45)
end
def draw
#message.draw(377.5,277.5,0)
end
end
window = GameWindow.new
window.show
My first approach was to take the height of the screen, subtract it by the height of the text 45, and then divide by 2. Now that seemed to work when aligning vertically.
However, horizontally is a different story...It seems to
be taking the top left corner of the text and centering it which I expected it to do, instead of the middle of the text.
Anyone got a formula for this ? I tried a whole bunch of things, and only came close.
class GameWindow < Gosu::Window
def initialize (width=800, height=600, fullscreen=false)
super
self.caption = 'Hello'
#message = Gosu::Image.from_text(
self, 'HELLO WORLD', Gosu.default_font_name, 45)
end
def draw
#message.draw(377.5,277.5,0)
end
end
Your #message is an instance of Gosu::Image
As far as I can see, the class has a method that allows you to align the image's rotational center to a specified point, draw_rot
Using draw_rot instead of draw should work for you once you've found the center of the frame.
I know this is an old question, but I was having this issue earlier today and came up with this solution.
def draw_centered_text(text, size, font)
centered_text = Gosu::Image.from_text(text, size, {:width => WIDTH, :align => :center, :font => font})
end
The above function converts the passed text to an image with a width equal to WIDTH (which in my case is a constant that stores the window width) and the text centred. You can then call the function like so:
draw_centered_text("Your text", 20, "Arial Bold").draw(0, 50, 0, 1, 1, Gosu::Color::WHITE)
You can replace 20 and 50 with any line height (font size) and y-position you want, just as you can change "Arial Bold" to "Arial" or any other font on your system. However, keep the 0 for the x-position (first parameter of draw()), since the centred text image is the same width as the window width.
See the links below for further information on from_text() and draw():
https://www.rubydoc.info/github/gosu/gosu/Gosu/Image#from_text-class_method
https://www.rubydoc.info/github/gosu/gosu/Gosu/Image#draw-instance_method
Better late than never...
No need to convert your text to an image. Just center the text using two parameters available on the Font.draw_text_rel method: rel_x and rel_y. See your code (modified a bit) below.
See: https://www.rubydoc.info/gems/gosu/Gosu%2FFont:draw_text_rel
require 'gosu'
class GameWindow < Gosu::Window
def initialize (width=800, height=600, fullscreen=false)
super
self.caption = 'Hello'
# #message = Gosu::Image.from_text(
# self, 'HELLO WORLD', Gosu.default_font_name, 45)
#font = Gosu::Font.new(45)
#message = "HELLO WORLD"
end
def draw
#font.draw_text_rel(#message, width / 2, height / 2, 1, rel_x = 0.5, rel_y = 0.5)
end
end
window = GameWindow.new
window.show
The line: pics.box.signal_connect("button_press_event"){pics.nuImage}, triggers nuImage and adds 1 to the picindex counter upon clicking, making the current image destroy, and next image show. I would like to make this automatic, like a slideshow without having to click. It needs to show a new image every x amount of seconds, using a sleep or something like GLib.timeout_add_seconds (), but I do not understand how to implement these options to continue looping without any user input. Thank you for your help, I am very new to ruby.
require 'gtk2'
class Pics
attr_accessor :pile, :picindex, :imgLoaded, :image, :box, :window, :time
def initialize
#window = Gtk::Window.new()
#window.signal_connect("destroy"){Gtk.main_quit}
pic1 = "1.jpg"
pic2 = "2.jpg"
pic3 = "3.jpg"
pic4 = "4.jpg"
#pile = [pic1, pic2, pic3, pic4]
#picindex = 0
self.getImage
#box = Gtk::EventBox.new.add(#image)
#time = true
end
def nuImage
#box.remove(#image)
#picindex = #picindex + 1
#picindex = 0 if #picindex == #pile.length
self.getImage
#box.add(#image)
#box.show
end
def getImage
#imgLoaded = #pile[#picindex]
img = Gdk::Pixbuf.new(#imgLoaded, 556, 900)
#image = Gtk::Image.new(img)
#image.show
end
end # class Pics
pics = Pics.new
pics.box.signal_connect("button_press_event"){pics.nuImage}
pics.window.set_default_size(556, 900)
pics.window.add(pics.box)
pics.window.show_all
Gtk.main
the following code is an implementation:
GLib::Timeout.add(1000) do
pics.nuImage if pics.time
true
end
pics.window.signal_connect("key_press_event") do |_window, event|
case event.keyval
when Gdk::Keyval::GDK_KEY_space
pics.time = !pics.time
end
end
more details: http://ruby-gnome2.sourceforge.jp/hiki.cgi?GLib%3A%3ATimeout
related: Ruby GTK Pixbuf timed image change
I was trying to make an image that raises a number by one when left clicked and lowers it when right clicked.
I was able to make shoes detect which button is clicked with the below code:
Shoes.app do
#info = para "No button pressed."
click do |button|
#info.replace "#{button} was PRESSED."
end
end
And this works just fine. LMB is 1, RMB is 2, and MMB is 3.
But when I try and detect a clicked image
Shoes.app do
number = 0
#image = image "image.png"
#info = para "No button pressed."
#image.click do |button|
#info.replace "#{button} was PRESSED."
end
end
It seems to only be passing self. The result, regardless of button, is "(Shoes::Image) was pressed." I cannot find any way to get around this problem.
What happens if you try this?
Shoes.app do
number = 0
#image = image "image.png"
#info = para "No button pressed."
#image.click do |button|
#info.replace "#{button.inspect} was PRESSED."
end
end
I think the click method of an element is designed to pass self as the block.
As far as I can see, the only way around it is to use the main click event and use the mouse position blocks to determine whether the mouse is over the image at the time of the click.
Shoes.app do
number = 0
#info = para "No button pressed."
#image = image "image.png"
click {|button, x, y|
if (x > #image.left) && (x < (#image.left + #image.width)) && (y > #image.top) && (y < (#image.top + #image.height))
#info.replace "#{button} was PRESSED."
end
}
end
Say I have the following sort of app:
Shoes.app do
#i = 0
def add_button
button ("#{#i += 1}")
end
button("0") {add_button}
end
So that each time you click the button it adds a new button with a higher number. Is there any way to code it so that clicking one of the new buttons displays its number? Since self always points to the app, the obvious approach
button ("#{#i += 1}") {alert #i}
Doesn't work, since then clicking any button just displays the current value of #i.
Shoes.app do
#i = 0
def add_button
n = #i+1
button ("#{#i += 1}") {alert n}
end
button("0") {add_button}
end