Crashes when clicking outside a grid.

First off - Hello.

I’m rather new to python (bout 2 months into it) and discovered wxPy a couple of days ago. We had a small introduction course of Python at school

and I couldn’t get enough, so I started learning a bit more on my own. I find that the best way to learn languages is to make up small projects for yourself,

so I decided to create a little number game, which I think most of us played in high school. The layout is very basic at this point and the game is

at its early stages but I’ve already run into a bit of a problem spot: The code is supposed to retrieve a cell’s value and coordinates when it’s clicked on

and then check if the next cell that is clicked on is

a) a neighbour cell

b) has an identical value or a sum of 10

This all works surprisingly fine and wxPy is a delight to work with. However, if I click outside of the game, it throws no error or anything, but the program

stops responding (“… has stopped working”) and windows asks me to Close the Program.

import wx
import wx.grid as gridlib

pair =
class MyForm(wx.Frame):
def init(self):
“”"
Constructor
“”"
wx.Frame.init(self, parent=None, title=“Getting the Row/Col”)
panel = wx.Panel(self)
myGrid = gridlib.Grid(panel)
myGrid.CreateGrid(3, 9)
self.myGrid = myGrid
self.myGrid.GetGridWindow().Bind(wx.EVT_LEFT_DOWN, self.onMouseDown)
self.myGrid.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self.whenRangeSelect)
myGrid.AutoSize()
myGrid.SetCellHighlightPenWidth(0)
myGrid.EnableEditing(False)
myGrid.EnableDragGridSize(False)
myGrid.DisableDragColSize()
myGrid.DisableDragRowSize()
line = 0
cell = 0
labels = [nr for nr in range(1,20)]
labels.remove(10)
for label in labels:
for digit in str(label):
if cell < 9:
myGrid.SetCellValue(line, cell, digit)
cell += 1
else:
cell = 0
line += 1
myGrid.SetCellValue(line, cell, digit)
cell = 1

    myGrid.SetRowLabelSize(0)
    myGrid.SetColLabelSize(0)
    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer.Add(myGrid, 1, wx.EXPAND)
    panel.SetSizer(sizer)
def onMouseDown(self, event):
    """
     Recognises which cell was clicked on and retrieves the value of clicked cell.
    """
    global pair
    x, y = self.myGrid.CalcUnscrolledPosition(event.GetX(), event.GetY())
    row, col = self.myGrid.XYToCell(x, y)
    val = [int(self.myGrid.GetCellValue(row, col)), row, col]
    if len(pair) == 0:
        pair.append(val)
        print(pair, len(pair))
    else:
        pair.append(val)
        if (pair[0][1] == pair[1][1] and (pair[0][2] + 1 == pair[1][2] or pair[0][2] -1 == pair[1][2])) or (pair[0][2] == pair[1][2] and (pair[0][1] +1 == pair[1][1] or pair[0][1] -1 == pair[1][1])):
            if pair[0][0] + pair[1][0] == 10 or pair[0][0] == pair[1][0]:
                print(pair, "Correct!")
                pair = []
            else:
                print(pair, "No dice")
                pair = []
        else:
            print("Numbers aren't neighbours!")
            pair = []
def whenRangeSelect(self, event):
    #self.myGrid.ClearSelection()
     if not self.clearingSelection:
         self.myGrid.clearingSelection = True
         self.myGrid.ClearSelection()
         self.myGrid.clearingSelection = False

if name == “main”:
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()

Since I do not know which part exactly is the reason for this issue, I posted the whole code I have so far. I guess the conflict is that with the left mouse click event, it tries

to GetX and GetY of the grid and there happens to be none. Would a try/except error handling correct this for me? How would you brighter minds go about this?

Also, I’ve searched but found no conclusive answer this far - is there a way to disable RangeSelect? The part that I have in my code right now is what I found from here on wxPython-Users,

but it doesn’t do the trick for me.

Could also use some comments on the code if some things could be done more efficiently perhaps. Still a rookie.

All help appreciated!

Andrew

Andrew wrote:

This all works surprisingly fine and wxPy is a delight to work with.
However, if I click outside of the game, it throws no error or
anything, but the program stops responding ("... has stopped working")
and windows asks me to Close the Program.
...

Since I do not know which part exactly is the reason for this issue, I
posted the whole code I have so far. I guess the conflict is that with
the left mouse click event, it tries
to GetX and GetY of the grid and there happens to be none. Would a
try/except error handling correct this for me? How would you brighter
minds go about this?

If the click is outside of the grid, XYToCell returns (-1, -1). When
you pass that the GetCellValue, it explodes. If you don't want to take
any action, just add:
    if row < 0 or col < 0:
        return

All I did hear was add some debugging prints. Any time you get
confusing results, start printing intermediate values so you can
validate your assumptions.

        print 1
        x, y = self.myGrid.CalcUnscrolledPosition(...)
        print x, y
        row, col = self.myGrid.XYToCell(...)
        print row, col

Could also use some comments on the code if some things could be done
more efficiently perhaps. Still a rookie.

The "if" statement that determines neighborness or not bothers me,
probably because it is so long, and does not scale well. What you want
to know is whether the X distance plus the Y distance is exactly 1. If
you think about it that way, you can do:

    if abs(pair[0][1]-pair[1][1]) + abs(pair[0][2]-pair[1][2]) == 1:

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Excellent, Tim! Thank you so much for the answer Sir!

If you don’t mind helping me on 2 other problems with the same code:

Once I’ve started “deleting” some of the numbers that match from my grid now,
I replace them with an empty string ’ ’ - is this the best way to do it or can I
leave a cell ‘valueless’ as well? Now that I’ve removed some of my
numbers, there
are gaps between numbers that I would like to match.
As the game progresses, the gaps could be 10 empty rows in length (I do plan on
having a button to remove the empty rows later on of course)…

How would I go about checking two numbers on either side of the gap?
I figured I could do this with a for loop (make my code count the number
of empty cells in between the two figures and then use that as the for
loop’s range) or a while
loop (while the GetCellValue finds ’ ’ in the cell, it continues to
search the next box until it
finds one with an integral and then checks if they match). Am I on the
right track here?

And for the second question:
Once a player is done crossing out the number pairs on the field -
he/she would click a
button and the game would have to write out (into the existing grid)
all the numbers left uncrossed.
How would I get all the integrals values that I have left on my grid
and how can I add new rows into my grid?
(Also, I might be adding rows with the right command/method right now,
but the rows aren’t showing, i.e. the grid
isn’t refreshing itself?)

What would be the difference? Remember that a grid is just a way to
display stuff, and each cell is nothing more than a string. So, an
empty string is the same as a “valueless” entry.
That could be made work, but really it depends on how much trouble
you want to go to.
A grid is just a way of displaying data. Usually, you don’t use it
to STORE your data as well, because all of those GetCellValue calls
are very slow. Instead, you would have a friendlier data structure
in your code that contains your real data, and when you change that
data structure, you go rebuild the grid so that the display reflects
your data structure.
So, if you had your own grid (stored as a list of lists, maybe,
although there are several other options), you could have each grid
cell include “pointers” to the next cell to the north, west, south,
and east. Then, when you remove a cell, you just update the
pointers in the cells surrounding it.
Is that worth the trouble? Well, it depends on which operations get
done more often.
Speaking from a more general point of view, I have found that one of
the things that marks the difference between a beginning programmer
and an advanced programmer is whether they focus on data. A
computer program is really just a process that manipulates some
chunk of data. When I think about writing a program, I think about
what data I need to maintain. Once I have the data structures
clearly in mind, it’s usually very easy to add code to construct
that data from input, to create output from the data, and to write
GUI controls to manipulate the data. When you focus on the GUI
first, there’s a tendency to end up with spaghetti code that has no
structure. When you focus on the data, then you can write good
tests that make sure the data is always coherent.
I don’t understand the question, I guess. One way to think about
this is to think about how you, as a human, would solve this. Say
you had an array of post office boxes in front of you, each with a
number. Some of them have been emptied. Now, how would you go
about do what you just asked? Would you start at the upper left and
gather items going across? Well, that maps pretty easily into a
couple of nested loops.
Without seeing your code, I can’t really comment on this.

···

Andrew wrote:

O nce I’ve
started “deleting” some of the numbers that match from my
grid now,

                  I replace them

with an empty string ’ ’ - is this the best way to do it or
can I

                  leave a cell

‘valueless’ as well?

Now that
I’ve removed some of my numbers, there are gaps between
numbers that I would like to match. As the game
progresses, the gaps could be 10 empty rows in length (I do
plan on having a button to remove the empty rows later
on of course)…

                  How would I go

about checking two numbers on either side of the gap?
I figured I
could do this with a for loop (make my code count the number
of empty
cells in between the two figures and then use that as the
for loop’s
range) or a while loop (while the GetCellValue finds ’ ’ in the
cell, it continues to search the next box until it finds one with an
integral and then checks if they match). Am I on the right track here?

                  And for the

second question:

                  Once a player is

done crossing out the number pairs on the field - he/she would click a
button and the
game would have to write out (into the existing grid) all the numbers left
uncrossed. How would I get all the integrals values that I
have left on my grid and how can I add new rows into my grid?

        (Also, I

might be adding rows with the right command/method right
now, but
the rows aren’t showing, i.e. the grid isn’t refreshing
itself?)

-- Tim Roberts, Providenza & Boekelheide, Inc.

timr@probo.com