self.mb = Menubutton ( self.window2, text="Sound Toggler", relief=RAISED )
self.mb.grid(row=4, column = 0)
self.mb.menu = Menu ( self.mb, tearoff = 0 )
self.mb["menu"] = self.mb.menu
self.ONSound = IntVar()
self.ONSound.set(1)
self.OFFSound = IntVar()
self.OFFSound.set(0)
self.mb.menu.add_checkbutton ( label="ONSound", variable=self.ONSound, command = self.turnON(), onvalue=1,offvalue=0)
self.mb.menu.add_checkbutton ( label="OFFSound", variable=self.OFFSound, command = self.turnOFF(), onvalue=1,offvalue=0)
def turnON(self):
self.ONSound.set(1)
self.OFFSound.set(0)
def turnOFF(self):
self.ONSound.set(0)
self.OFFSound.set(1)
My goal is to turn these two check buttons to toggle sound On and OFF and in doing so only one of these check buttons can be on/off at a single time. Currently this effect is not working and I've been looking at my code for an hour and can't find the problem. Everything shows up when my full program is run but this ON/OFF toggle doesn't work how I want it to.
All help is appreciated,
Thanks
The problem is that you set the command to a function call instead of a funciton reference. This makes the functions run once and assign the return value (None) to command. You should remove the parentheses after the function names.
To make two options of which only one can be selected however, why don't you make them radiobuttons? Then it's as simple as
self.Sound = IntVar()
self.mb.menu.add_radiobutton(label= "ONSound", variable=self.Sound, value=1)
self.mb.menu.add_radiobutton(label="OFFSound", variable=self.Sound, value=0)
Related
I want to draw a specific curve line to Photoshop or to mspaint. This drawing action should be saved for the possibility to redraw that curve in the exact same way. How can I do it with Autoit? Is there a recording and play mechanism? As far as I read, the AU3 recorder is not available anymore.
Photoshop is just an example. I want to be able to do that kind of drawing record for different purposes and programs. Maybe also for online image editors or something.
I am not that familiar with Autoit yet. I do not expect a full code example, maybe you can give me an idea - that would be very helpful.
Currently I tried a bit with mouse functions like MouseDown, MouseMove etc. and it is quite funny, but i do not really have a concept to record and redraw these mouse actions.
If I have to clarify more please let me know - i will do my best to be precise.
I recommend using two scripts, one for recording and the second to replay recorded actions.
Code for the recording:
; declaration
Global $sFileCoordinates = #ScriptDir & '\RecordedMouseMoveCoordinates.txt'
Global $iRecordingDurationInSeconds = 10
Global $iXSave, $iYSave
; functions
Func _recordMouseMoveCoordinatesToFile()
Local $aPos = MouseGetPos()
If $aPos[0] <> $iXSave Or $aPos[1] <> $iYSave Then
FileWrite($hFile, $aPos[0] & ',' & $aPos[1] & #CRLF)
Local $aPos = MouseGetPos()
$iXSave = $aPos[0]
$iYSave = $aPos[1]
EndIf
Sleep(80)
EndFunc
; processing
Sleep(4000) ; wait 4 seconds to place your mouse to the start position
Global $hFile = FileOpen($sFileCoordinates, 1 + 256)
Global $hTimer = TimerInit()
While Round((TimerDiff($hTimer) / 1000), 1) <= $iRecordingDurationInSeconds
ToolTip(Round((TimerDiff($hTimer) / 1000), 1))
_recordMouseMoveCoordinatesToFile()
WEnd
FileClose($hFile)
Recording will start after a 4 second delay. This should allow to move your mouse to the start point of your drawing action.
Global $iRecordingDurationInSeconds = 10 means your drawing action should be finished in 10 seconds (a tooltip displays remaining seconds). And here the seconds script.
Code to redraw curve:
; declaration
Global $sFileCoordinates = #ScriptDir & '\RecordedMouseMoveCoordinates.txt'
; functions
Func _getFileContent($sFile)
Local $hFile = FileOpen($sFile, 256)
Local $sFileContent = FileRead($hFile)
FileClose($hFile)
Return $sFileContent
EndFunc
Func _drawRecordedMouseMoveCoordinatesFromFile($sContent)
Local $aFileContent = StringSplit($sContent, #CRLF, 1)
Local $iX = StringSplit($aFileContent[1], ',')[1]
Local $iY = StringSplit($aFileContent[1], ',')[2]
MouseMove($iX, $iY, 4)
MouseDown('left')
For $i = 1 To $aFileContent[0] Step 1
If $aFileContent[$i] <> '' Then
Local $iX = StringSplit($aFileContent[$i], ',')[1]
Local $iY = StringSplit($aFileContent[$i], ',')[2]
MouseMove($iX, $iY, 4)
EndIf
Next
MouseUp('left')
EndFunc
; processing
Sleep(2000) ; wait 2 seconds till start
Global $sFileContent = _getFileContent($sFileCoordinates)
_drawRecordedMouseMoveCoordinatesFromFile($sFileContent)
There is a start delay of 2 seconds. All saved coordinates will be executed in the same way recorded. It starts with MouseDown('left'), then the mouse movements to MouseUp('left').
Notice:
This approach isn't really robust because of the coordinates which aren't relative to your window. Please see Opt('MouseCoordMode', 0|1|2) in the help file for more information. If you want to draw more than just one line or curve this approach isn't the best. But as your question describes only that requirement it should be fine.
I'm facing issues with multi-line figure in bokeh. i can't get the values when i show my graph. i'm using series data type.
Code:
df = pandas.read_csv("Data.csv", parse_dates=["time"])
result = df.groupby(['time','up','down'], as_index = False)['up', 'down'].sum()
p = Figure(width=500, height=250,logo =None,
sizing_mode='scale_width',
tools="pan, box_zoom, wheel_zoom, save, reset, box_select",
x_axis_type="datetime",
title="Graph:",
x_axis_label="Time Frame",
y_axis_label="Utilization (GB)",
toolbar_location="below",
toolbar_sticky=False)
up = result["up"]
time = result["time"]
down = result["down"]
p.multi_line(xs = [time, time], ys = [up, down], color=['#2828B0', '#BC0096'], line_width=1, legend='graph_1')
hover = HoverTool(tooltips = [('Time', '#time'),
('data', '#up')])
p.add_tools(hover)
p.show()
The # fields of hover tooltips refer to columns in Bokeh ColumnDataSource objects. Since you have not created a CDS explicitly with column names of your choice, Bokeh makes one for you with the standard column name xs and ys in this case. So:
HoverTool(tooltips = [
('Time', '#xs'),
('data', '#ys')]
)
That will put a hover that displays over all segments in the multi-line. There is no way to have a hover work for just one or the other. If you need that, you will have to use separate calls to line instead of multi_line.
This code is a simplified typing game, but I can't continue. The features required are:
Please don't use classes but just use FP;
When 5 random characters appear after you click the button, the 5 characters drop with a speed of 5 pixel/second, and meanwhile, you hit your keyboard to strike them. For every successful hit, your score wins by 10, and the character being hit will disappear. If not successful, they continue to drop untill the bottom edge of the canvas.
Below is part of my code, I've tried several times, but couldn't make it. How can I continue? Many thanks!
from Tkinter import *
from time import *
import string
import random
root = Tk ( )
root.title("Typing")
cvs = Canvas ( root , width=400 , height=350 , background="White" )
def Start():
s=random.sample("string.ascii_letters",5)
cvs.delete("rand")
return cvs.create_text(200,50,text=s,tags='rand',font=('Courier New',36,'normal'))
Button(root,text="Start",command=Start,width=30).pack()
cvs.pack ( )
root.mainloop ( )
You can animate an object by writing a function that draws one frame of animation, and then schedules itself to be called again in the future.
For example, to move a single object down the screen at five pixels a second you can use a function like this:
def animate(cvs, object_id):
# move down five pixels
cvs.move(object_id, 0, 5)
# call this function again in one second
# if the object is still on the screen
(x0,y0) = cvs.coords(object_id)
if y0 < cvs.winfo_height():
cvs.after(1000, animate, cvs, object_id)
You will have to modify that to handle more than one character, or call it once for each character. That decision is left up to you, this just illustrates the general technique.
Next, you can set up a binding to the <KeyPress> event, look at the character that was pressed, and if it matches something on the screen you can delete it. One simple way to keep track of what's on the screen is to map the characters to their canvas ids.
For example:
chars = {}
for char in random.sample(string.ascii_letters, 5):
obj_id = cvs.create_text(...)
chars[char] = obj_id
Now you'll have a dictionary that looks like:
{"a": 1, "X", 2, "y", 3, "f", 4, "B", 5}
You can now move or delete each canvas item by id.
Total pyqt novice here. Trying to automatically modify the widget to display different options when user selects certain option in combobox 2. IE if user selects 'Cliff Erosion' or 'Dune Erosion', I want the widget to refresh with additional comboboxes. Likewise, if they select back to 'Rising Tides' or 'Coastal Flooding' I'd like the widget to go back to original call. How do I refresh the widget?
from PyQt4.QtGui import *
# Create window
class Window(QWidget):
#This block adds features into the window init
def __init__(self):
QWidget.__init__(self)
self.setWindowTitle('Monterey Bay Sea Level Rise')
self.resize(300, 240)
self.addWidgets1()
def addWidgets1(self):
#Add drop-down list for selecting forecast year
self.year_lbl = QLabel("1. Select Forecast Year", self)
self.year_lbl.move(5,0)
year = QComboBox(self)
year.addItem('2030')
year.addItem('2060')
year.addItem('2100')
year.move(5,20)
#Add drop-down list for selecting hazard
self.hazard_lbl = QLabel("2. Select Coastal Hazard", self)
self.hazard_lbl.move(5,50)
hazard = QComboBox(self)
hazard.addItem('Rising Tides')
hazard.addItem('Coastal Storm Flooding')
hazard.addItem('Cliff Erosion')
hazard.addItem('Dune Erosion')
hazard.activated[str].connect(self.addWidget2)
hazard.move(5,70)
#Add drop-down list for inputing model intensity (s1,s2,s3)
self.intensity_lbl = QLabel("3. Select Intensity", self)
self.intensity_lbl.move(5,100)
intensity = QComboBox(self)
intensity.addItem('Low')
intensity.addItem('Mid')
intensity.addItem('High')
intensity.move(5,120)
def addWidget2(self,text):
#if hazard is cliff erosion or dune erosion we want to update the widget
#... to include wstorm,long_term AND no_change,stormier
if text == 'Cliff Erosion' or text == 'Dune Erosion':
print 'Hi'
self.type_lbl = QLabel("3. Select type of changes", self)
self.type_lbl.move(5,150)
types = QComboBox(self)
types.addItem('Long-term')
types.addItem('Storm induced')
types.move(5,180)
self.storm_lbl = QLabel("4. Select for stormier", self)
self.storm_lbl.move(5,150)
storm = QComboBox(self)
storm.addItem('No Change')
storm.addItem('Stormier')
storm.move(5,180)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
#window.resize(100, 60)
window.show()
sys.exit(app.exec_())
The normal way of adding widgets to a Qt application is to use layouts. They will calculate the preferred size and location of your widgets and update this when needed, e.g. when widgets are added or when the window is resized (note what happens when you make your window smaller during execution and compare it with my solution below). I'm certain that it's possible to do all the moving and resizing yourself, but QLayouts are really the way to go and I strongly recommend you use them too.
There are a few types of QLayouts but in your case I would use a QFormLayout. To my surprise the QFormLayout does have an addRow method but no corresponding removeRow. However I find that just showing/hiding the combo boxes when needed does the trick as well. I've adapted your example below.
Finally, even just showing or hiding the last two combo boxes will cause the layout to slightly move the first three. This is caused by the fact that the 4th label is the longest of them all. I find that annoying. Perhaps a better solution is to enable/disable the combo boxes when needed. This has the additional benefit of showing the user that these options even exist. See also the code below. A second alternative may be to use a QGridLayout (instead of a QFormLayout) and use setColumnMinimumWidth to set the first column to a size that will hold all possible labels.
from PyQt4 import QtGui
# Create window
class Window(QtGui.QWidget):
#This block adds features into the window init
def __init__(self):
QtGui.QWidget.__init__(self)
self.setWindowTitle('Monterey Bay Sea Level Rise')
self.resize(300, 240)
self.addWidgets1()
def addWidgets1(self):
self.layout = QtGui.QFormLayout()
self.setLayout(self.layout)
#Add drop-down list for selecting forecast year
# You don't need to set to parent of the widgets to self anymore, the
# layout will set the parent automatically when you add the widgets
self.year_lbl = QtGui.QLabel("1. Select Forecast Year")
# self.year_lbl.move(5,0) # Can be removed. The layout takes care of it.
year = QtGui.QComboBox()
year.addItem('2030')
year.addItem('2060')
year.addItem('2100')
self.layout.addRow(self.year_lbl, year)
#Add drop-down list for selecting hazard
self.hazard_lbl = QtGui.QLabel("2. Select Coastal Hazard")
self.hazard = QtGui.QComboBox()
self.hazard.addItem('Rising Tides')
self.hazard.addItem('Coastal Storm Flooding')
self.hazard.addItem('Cliff Erosion')
self.hazard.addItem('Dune Erosion')
self.hazard.activated[str].connect(self.updateComboboxes)
self.layout.addRow(self.hazard_lbl, self.hazard)
#Add drop-down list for inputing model intensity (s1,s2,s3)
self.intensity_lbl = QtGui.QLabel("3. Select Intensity")
intensity = QtGui.QComboBox()
intensity.addItem('Low')
intensity.addItem('Mid')
intensity.addItem('High')
self.layout.addRow(self.intensity_lbl, intensity)
self.types_lbl = QtGui.QLabel("3. Select type of changes")
self.types = QtGui.QComboBox()
self.types.addItem('Long-term')
self.types.addItem('Storm induced')
self.layout.addRow(self.types_lbl, self.types)
self.storm_lbl = QtGui.QLabel("4. Select for stormier")
self.storm = QtGui.QComboBox()
self.storm.addItem('No Change')
self.storm.addItem('Stormier')
self.layout.addRow(self.storm_lbl, self.storm)
# show initial state
self.updateComboboxes()
def updateComboboxes(self, text=None):
#if hazard is cliff erosion or dune erosion we want to update the widget
#... to include wstorm,long_term AND no_change,stormier
if text is None:
text = self.hazard.currentText()
usable = (text == 'Cliff Erosion' or text == 'Dune Erosion')
if True: # change to False to use enabling/disabling widgets
# May cause other widgets to be relocated
self.types_lbl.setVisible(usable)
self.types.setVisible(usable)
self.storm_lbl.setVisible(usable)
self.storm.setVisible(usable)
else:
# This option doesn't relocate widgets
# Also may give additional clue to the uses that this exsits
self.types_lbl.setEnabled(usable)
self.types.setEnabled(usable)
self.storm_lbl.setEnabled(usable)
self.storm.setEnabled(usable)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
#window.resize(100, 60)
window.show()
sys.exit(app.exec_())
def nextItem(self):
active = self.skill_list_listbox.get(tk.ACTIVE)
listbox_contents = self.skill_list_listbox.get(0, tk.END)
current_pos = listbox_contents.index(active)
if current_pos + 1 < len(listbox_contents):
new_pos = current_pos + 1
self.skill_list_listbox.activate(new_pos)
self.skill_list_listbox.selection_set(tk.ACTIVE)
From what I can see within documentation this should highlight and activate the next item in the listbox. If I omit the selection_set I get what I'm looking for but there's no indicator of what's active. Adding it highlights an item, but if you continue to click the "next" button it simply adds to the highlight instead of just highlighting one item creating a long section of highlighted items, which I don't want. I've tried several different methods and this has got me the closest. If there was a 'clear selection' method I suppose I could get my desired effect of just having the next item selected and highlighted, but 3 calls just to do that seems a bit much for a common task? Any thoughts, or suggestions?
Below is an example of what I think you are trying to accomplish, using a button to select the next item in a Listbox. The gist of it is in the button's callback function, which calls selection_clear then selection_set.
Updated the example, hopefully a bit clearer as to what it happening
import Tkinter
class Application(Tkinter.Frame):
def __init__(self, master):
Tkinter.Frame.__init__(self, master)
self.master.minsize(width=256, height=256)
self.master.config()
self.pack()
self.main_frame = Tkinter.Frame()
self.some_list = [
'One',
'Two',
'Three',
'Four'
]
self.some_listbox = Tkinter.Listbox(self.main_frame)
self.some_listbox.pack(fill='both', expand=True)
self.main_frame.pack(fill='both', expand=True)
# insert our items into the list box
for i, item in enumerate(self.some_list):
self.some_listbox.insert(i, item)
# add a button to select the next item
self.some_button = Tkinter.Button(
self.main_frame, text="Next", command=self.next_selection)
self.some_button.pack(side='top')
# not really necessary, just make things look nice and centered
self.main_frame.place(in_=self.master, anchor='c', relx=.5, rely=.5)
def next_selection(self):
selection_indices = self.some_listbox.curselection()
# default next selection is the beginning
next_selection = 0
# make sure at least one item is selected
if len(selection_indices) > 0:
# Get the last selection, remember they are strings for some reason
# so convert to int
last_selection = int(selection_indices[-1])
# clear current selections
self.some_listbox.selection_clear(selection_indices)
# Make sure we're not at the last item
if last_selection < self.some_listbox.size() - 1:
next_selection = last_selection + 1
self.some_listbox.activate(next_selection)
self.some_listbox.selection_set(next_selection)
root = Tkinter.Tk()
app = Application(root)
app.mainloop()