I tried a lot already, would appreciate any help.
我已经尝试了很多,如果有任何帮助,我将不胜感激。
I built a state machine Dashboard with pytransitions and a dashboard with pywebio. Now im trying to have two buttons:
我构建了一个带有pytransitions的状态机Dashboard和一个带有pywebio的Dashboard。现在我试着有两个按钮:
def btn_click(btn_val):
global Lang
if btn_val=='English':
Lang=1
Dashboard.to_Start()
if btn_val=='German':
Lang=2
Dashboard.to_Start()
while True:
match Dashboard.state:
case 'Start':
clear()
put_buttons(['German', 'English'], onclick=btn_click)
match Lang:
case 1:
put_text("some english text")
case 2:
put_text("some german text")
Dashboard.ok()
case 'State2':
#do this and that
Dashboard.ok()
case 'State3':
#do this and that
match Lang:
case 1:
name = input("What's your name")
case 2:
name = input("Wie heisst du?")
which call a function, in which the variable for the different languages of my dashboard can be set. I also want the dashboard to completely refresh when the language is changed aka i want the state machine to change its state to the initial state Start. This should also happen, when the Dashboard is waiting for human text input like in state3. The buttons stay on screen the whole time, even in state2 and state3.
它调用一个函数,在该函数中可以设置仪表板不同语言的变量。我还希望仪表板在语言更改时完全刷新,也就是说,我希望状态机将其状态更改为初始状态Start。当Dashboard像状态3中那样等待人工文本输入时,也应该发生这种情况。即使在状态2和状态3中,按钮也始终显示在屏幕上。
Unfortunately, when i try to do that (the method to_Start()) in the function, it doesnt work. Funny enough, when i print out state machine state in the function, it prints its in the Start state, but not anymore after we are leaving the function. Which i understand has something to do with the fact that only local stuff is processed in functions (except for when defining global variables).
I also tried onclick=Dashboard.to_Start(), it doesnt work that way and i would run into the next problem, which would be that my variable Lang needs to be changed.
I guess it would be best if i could call the function btn_click AND Dashboard.to_Start() from onclick. Or maybe my whole approach is bad and i would be happy to hear some advice.
我想最好能从onclick调用函数btn_click AND Dashboard.to_Start()。或者,也许我的整个方法很糟糕,我很乐意听到一些建议。
Can someone please explain what i am missing here?
有人能解释一下我在这里缺了什么吗?
Edit: Im not getting an error message at all or pywebio tells me on the dashboard that an "internal error occured". In the comments my code example was critiziced, i did my best to improve on that.
编辑:我根本没有收到错误消息,或者pywebio告诉我“发生了内部错误”。在评论中,我的代码示例受到了批评,我尽了最大努力对此进行改进。
Im getting mad crazy over this, please help. Cheers and Regards
我被这件事弄疯了,请帮帮我。干杯和问候
更多回答
(1) The shown code is syntactically incorrect and has incorrect indentation. (2) If there is an error message, show it completely as properly formatted text in the question.
(1) 显示的代码语法不正确,并且缩进不正确。(2) 如果有错误消息,请将其完全显示为问题中格式正确的文本。
优秀答案推荐
Welcome to Stack Overflow, Toben.
欢迎来到Stack Overflow,Toben。
Since I cannot test your code directly I went ahead and created a MRE myself. But first, some remarks:
由于我不能直接测试你的代码,我自己创建了一个MRE。但首先,请注意:
A) Switch/match case statements and state machines
One argument for state machines is to get rid of complex switch/case statements. If you track your machines states with (polling) switch/case statements, either the machine or switch/case might not be the right choice here.
状态机的一个论点是去掉复杂的switch/case语句。如果您使用(轮询)switch/case语句跟踪机器状态,那么在这里,机器或switch/case可能不是正确的选择。
B) State machines and GUI/interactive applications:
Many networking and GUI frameworks handle user or network input asynchronously (e.g. in threads) and use/block the main thread for changes to the GUI. Furthermore, most state machine implementations -- transitions' Machine
included -- are not thread-safe. Transitions features LockedMachine
for threaded and AsyncMachine
for async/await use cases.
许多网络和GUI框架异步处理用户或网络输入(例如在线程中),并使用/阻止主线程来更改GUI。此外,大多数状态机实现——包括机器的转换——都不是线程安全的。Transitions的特点是LockedMachine用于线程,AsyncMachine用于异步/等待用例。
For my minimal example I will ignore B) since it depends on the chosen framework whether threading or asynchronous event processing is the more suitable approach. But let's face A) now: Instead of polling the machine's state, we use an event-driven approach where create a controller to handle GUI changes based on user input and pass this to the state machine as a state model. The separation of machine and stateful model is the recommended way of working with transitions. Machines can be considered rulebooks that can be used for more than one stateful object.
对于我的最小示例,我将忽略B),因为它取决于所选的框架,线程还是异步事件处理是更合适的方法。但现在让我们面对A):我们使用事件驱动的方法,而不是轮询机器的状态,创建一个控制器来处理基于用户输入的GUI更改,并将其作为状态模型传递给状态机。机器和有状态模型的分离是处理转换的推荐方法。机器可以被视为可用于多个有状态对象的规则手册。
from pywebio.output import put_text, put_buttons, clear
from pywebio import start_server
from transitions import Machine
# Our GUI controller/stateful model contains all methods that will
# alter the GUI and process input events. Each method may receive
# input information.
class WebIOModel:
def on_enter_Start(self, inp=None):
# We bind the button's onclick callback to a yet
# to be defined "clicked" method.
put_buttons(["German", "English"], onclick=self.clicked)
put_text("Choose a language")
def on_enter_Clicked(self, inp=None):
put_text(f"You chose {inp}")
def clear_canvas(self, inp=None):
clear()
# Our simple machine has three states
# Pay attention to the state names and the method names of our
# WebIOModel: transitions will automatically bind methods to
# state events that match the pattern "on_enter_<state>"
# and "on_exit_<state>".
states = ["Init", "Start", "Clicked"]
# We create a transition event named "clicked".
# When the state machine is
# in state "Start" and "clicked" happens, the machine will transition
# to state "Clicked" and also execute callbacks associated with
# exiting "Start" and entering "Clicked".
transitions = [["clicked", "Start", "Clicked"]]
model = WebIOModel()
# We tell our machine that it should always execute the model's
# callback "clear_canvas" before a state transition.
# We use this callback to clear the GUI and reduce redundant code.
# Note that for "enter_<state>" callbacks to be called, a state
# must be actually entered. However, an "initial" state is not
# entered. We create a dummy "Init" state to deal with this.
machine = Machine(
model,
states=states,
transitions=transitions,
before_state_change="clear_canvas",
initial="Init",
)
def main():
# Note that events and trigger functions are bound to the model
# not the machine! 'to_Start' will enter this state and draw the
# buttons
model.to_Start()
start_server(main, 80)
When the user clicks a button the onclick
callback is forwarded to our model's clicked
event. Since onclick
returns a value, our callback chain needs to be able to handle inputs. This is way each callback in WebIOModel
has an optional input
argument. The value passed to clicked
will be forwarded to all callbacks in the processing chain. Callbacks can be called at any state of a transition/event processing chain. The complete list and their execution order can be found in the documentation.
当用户单击按钮时,onclick回调将转发到我们模型的单击事件。由于onclick返回一个值,我们的回调链需要能够处理输入。WebIOModel中的每个回调都有一个可选的输入参数。传递给单击的值将转发到处理链中的所有回调。回调可以在转换/事件处理链的任何状态下调用。完整的列表及其执行顺序可以在文档中找到。
This is not production code since it ignore B) as mentioned before. Whether you queue user input events and process state changes in the main thread or whether you queue GUI events with a thread-safe LockedMachine
or via async/await depends on your architecture and PyWebIO
.
这不是生产代码,因为它忽略了前面提到的B)。是在主线程中对用户输入事件和进程状态更改进行排队,还是使用线程安全的LockedMachine或通过async/await对GUI事件进行排队,取决于您的体系结构和PyWebIO。
更多回答
我是一名优秀的程序员,十分优秀!