I am making a battleship game for a project. While I have completed the logic and the game works with text input. I was hoping make a (very basic) GUI while still use the methods created for the text.
The two options I've been looking at are PyGame and Tkinter. PyGame does not seem to have a text output/label function. Tkinter does, but it doesn't seem as easy (i feel) as PyGame is.
Though I would love to give either of these frameworks the time they deserve, I have just over 60hrs before this is due.
I wanted to know if anyone one has any experience or insights and if it is a realistic option.
Thanks as always!
This is a fairly trivial thing to do in Tkinter. A battleship game shows an array of coordinates which you can display as a grid of checkbuttons.
You could check Kivy, it's working in top of OpenGL, provide severals basics widgets (label, button, slider, textinput, layouts, ...), and you can create your own / display graphics etc. Works as a python framework, almost all platforms.
You can also check the recent game contest to see what you can do with it :)
Why don't you try Cocos2D?
It's higher level, and it supports rich labeling (Class cocos.text.RichLabel)
http://cocos2d.org/
I suggest you use pyqt/pyside for this task. This lets you access the powerful Qt framework which has great documentation. If you design a game that does not need fast graphics you can simply use QGraphicsView/QGraphicsScene and related classes to display icons/numbers/whatever. Of course you can use OpenGL with Python and Qt as well.
You can render text on pygame, just use:
class pygame.font.Font
#create a new Font object from a file
pygame.font.Font(filename, size): return Font
pygame.font.Font(object, size): return Font
method Font.render
#method of Font() to draw text on a new Surface
Font.render(text, antialias, color, background=None): return Surface
Simple example how to use text on pygame:
from pygame import font as pgfont, sprite as pgspr
import pygame as pg
class FontSprite(pgspr.DirtySprite):
def __init__(self, text, x, y):
'''self.image = surface'''
pgspr.DirtySprite.__init__(self)
self.text = text
self.color = [0,0,0]
self.image = self.get_image()
self.rect = pg.Rect((x, y), self.image.get_size())
def get_image(self):
self.dirty = 1
return pgfont.Font('fonts\\BRLNSR.TTF', self.size).render(self.text,
True,
self.color)
Related
This question already has answers here:
How can I create a text input box with Pygame?
(5 answers)
Closed 3 years ago.
All I need right now is basic text fields and buttons for input in pygames. A text field as some simple structure that I can read into variables, and a button to call a function.
First, I browsed around and found it was not a straight-forward process to create a text field in pygames. Eventually, by cobbling together this wall of code, I became the proud father of one, somewhat broken text field. Then I looked into buttons, and found to some horror that implementing them is even more complicated.
Surely PyGame has some sort of buttons module built in right? No.
Excuse me? I'm not trying to write a whole program just for one button, I just need the interface for a deeper simulation. That's all.
So then I looked into Tkinter, which has very easy-to-understand commands for GUI input. But no, that was also not meant to be.
I don't believe you can embed tkinter in to pygame.
So then I tried PGU, but found a stunning lack of any straight-forward examples of how to actually use it for what I need (simple text fields and buttons). When I tried looking for one, I found this piece of wisdom.
Are there any good, modern widget toolkits for Pygame? No. Every year someone makes a new Pygame UI library and then abandons it after a few versions
So if that was true, how is anyone supposed to get anything done with this language? What exactly is the best practice for a simple textfield and simple button in a pygame environment?
yes - pygame is barebones "we control the pixels" - and has been around a lot of time, and itself looked like abandoned for a lot of time (it was just in late 2016 that it would install clean on Python 3, for example). So, in the meantime pygame looked abandoned people moved away.
For the time being, you have to try your luck mining a usable toolkit from here:
https://www.pygame.org/wiki/gui
The PGU toolkit listed there, as you noted, seems quite complete - bar examples on how to build simple widgets to interact with an existing Pygame codebase. All the examples assume one wants to just have an stand alne gui application for form filling, which, I agree, is quite inapropriate: if one wants this kind of application, just use Tkiner, Qt or create a web app.
It turns out, however, that using a standalone widget in an existing pygame window is quite simple. Despite all the library examples calling the .run method, which is the spoiler part, since nce you call run the PGU app takes over and there is no way to run your code back, save for callbacks. However, the run method itself consist of a very simple infinite loop, calling the app's loop method. You just have to put a call to app.loop in all frames of your own pygame loop and have the widgets working.
It will swallow pygame events, however - if you want to treat event while you are displaying widgets, you should dispatch all events to app.event and call app.update instead of calling app.loop. It is trivial once you look at the source code for the app class at https://github.com/parogers/pgu/blob/master/pgu/gui/app.py
So, a complete example for using a text-input can be:
import pygame
from pgu import gui
SIZE = W, H = 800, 600
def bouncing_rect(screen):
surf = pygame.Surface((50, 50))
rect = surf.get_rect()
surf.fill((255, 0, 0))
vx, vy = 10, 10
while True:
screen.blit(surf, rect)
new_surface = yield rect
if new_surface:
surf = new_surface
rect.width = surf.get_width()
rect.height = surf.get_height()
rect.x += vx
rect.y += vy
if rect.right > W or rect.left < 0:
vx = -vx
rect.x += vx * 2
if rect.bottom > H or rect.top < 0:
vy = -vy
rect.y += vy * 2
def main():
screen = pygame.display.set_mode((SIZE))
app = gui.Desktop()
txt = gui.Input()
app.init(widget=txt, screen=screen, area=pygame.Rect(50, 50, 200,25))
bouncing = bouncing_rect(screen)
previous_value = ""
font = pygame.font.SysFont(name="Sans", size=30)
while True:
screen.fill((0,0,0))
rect = next(bouncing)
app.loop()
if txt.value != previous_value:
previous_value = txt.value
rect = bouncing.send(font.render(txt.value, True, (255, 255, 0)))
pygame.display.update([rect])
app.repaint()
pygame.display.flip()
pygame.time.delay(30)
try:
main()
finally:
pygame.quit()
(I just made the bouncing object as generator function using the "send" method, since there are very few examples of this pattern, but it could be a class just the same - if it were a common pygame.Sprite child class, I'd just call "update" instead of using next/send. )
I am looking for a way in which wxPython GUI elements can be added into pygame. If there is an alternative to solve the purpose of adding GUI elements to a pygame please suggest so. I am having problem in installing PGU.Thanks for help.
Nope; you CAN add wxWidgets to PyGame. It's trivial to add open/save dialogs, buttons, etc. Sometimes it gets nasty when you try to share areas, (as above, there's conflicting window systems), but it is definitely doable.
I wrote the following years ago, so it's messy; but at least it's simple. It should help you get started:
class SDLThread:
def __init__(self,screen):
self.m_bKeepGoing = self.m_bRunning = False
self.screen = screen
self.color = (255,0,0)
self.rect = (10,10,100,100)
def Start(self):
self.m_bKeepGoing = self.m_bRunning = True
thread.start_new_thread(self.Run, ())
def Stop(self):
self.m_bKeepGoing = False
def IsRunning(self):
return self.m_bRunning
def Run(self):
while self.m_bKeepGoing:
pass
## GetInput()
## Draw()
self.m_bRunning = False;
class SDLPanel(wx.Panel):
def __init__(self,parent,ID,tplSize):
global pygame
wx.Panel.__init__(self, parent, ID, size=tplSize)
self.Fit()
os.environ['SDL_WINDOWID'] = str(self.GetHandle())
os.environ['SDL_VIDEODRIVER'] = 'windib'
import pygame
pygame.init()
icon = pygame.Surface((1,1));icon.set_alpha(0);pygame.display.set_icon(icon)
global Surface
Surface = pygame.display.set_mode(tplSize)
self.thread = SDLThread(Surface)
self.thread.Start()
def __del__(self):
self.thread.Stop()
I dont think its possible since wxPython (using wxWidgets c++) is a wrapper around the window management system, it rely on the OS functions to draw on screen (it convert to the right system calls depending on OS).
Pygame uses SDL and a simple code to window management system, it calls few OS functions just to create the window and give it to SDL to draw on it, like a canvas.
One way is:
using ctypes to make C calls into OS library files to draw system native widgets, this way you aren't using any pygame functions.
Other way(ugly and not sure if works):
I dont know how, but finding a way to convert widgets into image buffer objects and use it like surfaces(plain bitmaps).
What I think you should do:
Use pygame, build your own GUI using surfaces and mouse/keyboard events to control it or download some pre-made.
Stick with wx, you can build your GUI easily on system native theme, also you can use DC (draw contexts) to draw like pygame, and maybe (not sure) include pygame context into wx as one widget.
You can benefit from wx having its own event handler.
I hope it helps you in some way.
I am using VPython in my attempt to model a ball bouncing off a wall.
To make my code more elegant, I have decided to use class inheritance to set the dimensions and properties of my objects (at the moment, it's the ball and a wall). After I ran the code, the shell didn't produce any errors, however, it did not produce a window either.
I am fairly new to programming and I am using VPython 2.7 in Wine on Linux Mint 18. I have a feeling that I have missed something obvious but I don't know what it is.
My code so far is as follows:
from visual import *
class Obj(object):
def __init__(self, pos, color): #sets the position and color
self.pos = pos
self.color = color
class Sphere(Obj):
def __init__(self, pos, color, radius):
super(Sphere, self).__init__(pos, color)
self.radius = radius
class Box(Obj):
def __init__self, pos, color, radius):
super(Box, self).__init__(pos, color)
self.size = size
self.opacity = opacity
ball1 = Sphere((-5,0,0,), color.orange, 0.25)
wallR = Box((6,0,0), color.cyan, (0.,12,12), 0.3)
I take it you never dealt with graphic aspects before, as there is nothing about it in the code you posted. Then it is time to begin !
By default, python works in console mode. To show an actual window, with icons and stuff going across it, you'll need to write it explicitly in your code, using modules like TKinter or pygame.
I suggest you read the tutorial I found here : http://code.activestate.com/recipes/502241-bouncing-ball-simulation/ as it does what you want (with TKinter), including the window part. Take a look at it and let's see if you still need help !
I am new to Python and have been working with the turtle module as a way of learning the language.
Thanks to stackoverflow, I researched and learned how to copy the image into an encapsulated postscript file and it works great. There is one problem, however. The turtle module allows background color which shows on the screen but does not show in the .eps file. All other colors, i.e. pen color and turtle color, make it through but not the background color.
As a matter of interest, I do not believe the import of Tkinter is necessary since I do not believe I am using any of the Tkinter module here. I included it as a part of trying to diagnose the problem. I had also used bgcolor=Orange rather than the s.bgcolor="orange".
No Joy.
I am including a simple code example:
# Python 2.7.3 on a Mac
import turtle
from Tkinter import *
s=turtle.Screen()
s.bgcolor("orange")
bob = turtle.Turtle()
bob.circle(250)
ts=bob.getscreen()
ts.getcanvas().postscript(file = "turtle.eps")
I tried to post the images of the screen and the .eps file but stackoverflow will not allow me to do so as a new user. Some sort of spam prevention. Simple enough to visualize though, screen has background color of orange and the eps file is white.
I would appreciate any ideas.
Postscript was designed for making marks on some medium like paper or film, not raster graphics. As such it doesn't have a background color per se that can be set to given color because that would normally be the color of the paper or unexposed film being used.
In order to simulate this you need to draw a rectangle the size of the canvas and fill it with the color you want as the background. I didn't see anything in the turtle module to query the canvas object returned by getcanvas() and the only alternative I can think of is to read the turtle.cfg file if there is one, or just hardcode the default 300x400 size. You might be able to look at the source and figure out where the dimensions of the current canvas are stored and access them directly.
Update:
I was just playing around in the Python console with the turtle module and discovered that what the canvas getcanvas() returns has a private attribute called _canvas which is a <Tkinter.Canvas instance>. This object has winfo_width() and winfo_height() methods which seem to contain the dimensions of the current turtle graphics window. So I would try drawing a filled rectangle of that size and see if that gives you what you want.
Update 2:
Here's code showing how to do what I suggested. Note: The background must be drawn before any other graphics are because otherwise the solid filled background rectangle created will cover up everything else on the screen.
Also, the added draw_background() function makes an effort to save and later restore the graphics state to what it was. This may not be necessary depending on your exact usage case.
import turtle
def draw_background(a_turtle):
""" Draw a background rectangle. """
ts = a_turtle.getscreen()
canvas = ts.getcanvas()
height = ts.getcanvas()._canvas.winfo_height()
width = ts.getcanvas()._canvas.winfo_width()
turtleheading = a_turtle.heading()
turtlespeed = a_turtle.speed()
penposn = a_turtle.position()
penstate = a_turtle.pen()
a_turtle.penup()
a_turtle.speed(0) # fastest
a_turtle.goto(-width/2-2, -height/2+3)
a_turtle.fillcolor(turtle.Screen().bgcolor())
a_turtle.begin_fill()
a_turtle.setheading(0)
a_turtle.forward(width)
a_turtle.setheading(90)
a_turtle.forward(height)
a_turtle.setheading(180)
a_turtle.forward(width)
a_turtle.setheading(270)
a_turtle.forward(height)
a_turtle.end_fill()
a_turtle.penup()
a_turtle.setposition(*penposn)
a_turtle.pen(penstate)
a_turtle.setheading(turtleheading)
a_turtle.speed(turtlespeed)
s = turtle.Screen()
s.bgcolor("orange")
bob = turtle.Turtle()
draw_background(bob)
ts = bob.getscreen()
canvas = ts.getcanvas()
bob.circle(250)
canvas.postscript(file="turtle.eps")
s.exitonclick() # optional
And here's the actual output produced (rendered onscreen via Photoshop):
I haven't found a way to get the canvas background colour on the generated (Encapsulated) PostScript file (I suspect it isn't possible). You can however fill your circle with a colour, and then use Canvas.postscript(colormode='color') as suggested by #mgilson:
import turtle
bob = turtle.Turtle()
bob.fillcolor('orange')
bob.begin_fill()
bob.circle(250)
bob.begin_fill()
ts = bob.getscreen()
ts.getcanvas().postscript(file='turtle.eps', colormode='color')
Improving #martineau's code after a decade
import turtle as t
Screen=t.Screen()
Canvas=Screen.getcanvas()
Width, Height = Canvas.winfo_width(), Canvas.winfo_height()
HalfWidth, HalfHeight = Width//2, Height//2
Background = t.Turtle()
Background.ht()
Background.speed(0)
def BackgroundColour(Colour:str="white"):
Background.clear() # Prevents accumulation of layers
Background.penup()
Background.goto(-HalfWidth,-HalfHeight)
Background.color(Colour)
Background.begin_fill()
Background.goto(HalfWidth,-HalfHeight)
Background.goto(HalfWidth,HalfHeight)
Background.goto(-HalfWidth,HalfHeight)
Background.goto(-HalfWidth,-HalfHeight)
Background.end_fill()
Background.penup()
Background.home()
BackgroundColour("orange")
Bob=t.Turtle()
Bob.circle(250)
Canvas.postscript(file="turtle.eps")
This depends on what a person is trying to accomplish but generally, having the option to select which turtle to use to draw your background to me is unnecessary and can overcomplicate things so what one can do instead is have one specific turtle (which I named Background) to just update the background when desired.
Plus, rather than directing the turtle object via magnitude and direction with setheading() and forward(), its cleaner (and maybe faster) to simply give the direct coordinates of where the turtle should go.
Also for any newcomers: Keeping all of the constants like Canvas, Width, and Height outside the BackgroundColour() function speeds up your code since your computer doesn't have to recalculate or refetch any values every time the function is called.
Got this question from a professor, a physicist.
I am a beginner in Python programming. I am not a computer professional I am a physicist. I was trying to write a code in python for my own research which involves a little image processing.
All I need to do is to display an image and then select a region of interest using my mouse and finally crop out the selected region. I can do this in Matlab using the ginput() function.
I tried using PIL. But I find that after I issue the command Image.show(), the image is displayed but then the program halts there unless I exit from the image window. Is there any way to implement what I was planning. Do I need to download any other module? Please advise.
While I agree with David that you should probably just use GIMP or some other image manipulation program, here is a script (as I took it to be an exercise to the reader) using pygame that does what you want. You will need to install pygame as well as the PIL, usage would be:
scriptname.py <input_path> <output_path>
Actual script:
import pygame, sys
from PIL import Image
pygame.init()
def displayImage( screen, px, topleft):
screen.blit(px, px.get_rect())
if topleft:
pygame.draw.rect( screen, (128,128,128), pygame.Rect(topleft[0], topleft[1], pygame.mouse.get_pos()[0] - topleft[0], pygame.mouse.get_pos()[1] - topleft[1]))
pygame.display.flip()
def setup(path):
px = pygame.image.load(path)
screen = pygame.display.set_mode( px.get_rect()[2:] )
screen.blit(px, px.get_rect())
pygame.display.flip()
return screen, px
def mainLoop(screen, px):
topleft = None
bottomright = None
runProgram = True
while runProgram:
for event in pygame.event.get():
if event.type == pygame.QUIT:
runProgram = False
elif event.type == pygame.MOUSEBUTTONUP:
if not topleft:
topleft = event.pos
else:
bottomright = event.pos
runProgram = False
displayImage(screen, px, topleft)
return ( topleft + bottomright )
if __name__ == "__main__":
screen, px = setup(sys.argv[1])
left, upper, right, lower = mainLoop(screen, px)
im = Image.open(sys.argv[1])
im = im.crop(( left, upper, right, lower))
im.save(sys.argv[2])
Hope this helps :)
For what it's worth (coming from another physicist), I would just do this in an image processing program like the GIMP. The main benefit of doing this task in Python (or any language) would be to save time by automating the process, but unless you - well, the professor - can somehow develop an algorithm to automatically figure out what part of the image to crop, there doesn't seem to be much time to be saved by automation.
If I remember correctly, GIMP is actually scriptable, possibly with Python, so it might be possible to write a time-saving GIMP script to do what your professor friend wants.
Image.show() just calls whatever simple picture viewer it can find on the current platform, one that may or may not have a crop-and-save facility.
If you are on a Windows box and you just need to make it work on your machine, set the ‘Open with...’ association to make it so running an image loads it into an editor of your choice. On OS X and *nix you'd want to hack the _showxv() method at the bottom of Image.py to change the command used to open the image.
If you do actually need to provide a portable solution, you'll need to use a UI framework to power your cropping application. The choices boil down to Tkinter (ImageTk.py gives you a wrapper for displaying PIL images in Tk), PyQT4 (ImageQt in PIL 1.1.6 gives you a wrapper for displaying images in QT4) or wxPython (a higher-level application authoring toolkit using wxWidgets). It'll be quite a bit of work to get the hang of a full UI kit, but you'll be able to completely customise how your application's interface will work.
Is there a script in python like a library to auto crop images :
Automatically crop image
What you are looking for is the module: matplotlib, it emulates Matlab. See the ginput() function. That allow you to find the bounding box, then you can use crop from PIL.
http://matplotlib.sourceforge.net/api/figure_api.html