保持控制台输入行在输出下方
[编辑:] 目前我正在尝试制作一个小的TCP聊天应用程序。发送和接收消息的功能已经正常工作了……但是问题是:
当我在接收消息的同时开始输入消息时,接收到的消息会出现在我正在输入的文本之后。
截图:http://s7.directupload.net/images/140816/6svxo5ui.png
[用户发送了 > "hello",然后我开始写 "i am writing...",接着用户写了 "i sent a...",在我发送我的消息之前……所以这条消息被放在了我的输入之后……我希望接收到的消息总是出现在我的输入之前!
这是我现在的代码:
Client.py
con = connect.User()
server = raw_input("Type in the server adress \n[leave blank to use xyr.no-ip.info]\n>:")
nick =""
while nick == "":
nick = raw_input("Type in your nickname\n>:")
con.connect(server, nick)
def sender():
print("Sender started")
while 1:
msg = raw_input()
if msg == "q":
break
con.send(msg)
con.disconnect()
def receiver(server):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server == "":
server="xyr.no-ip.info"
sock.connect((server, 8000))
sock.send("%pyreceiver\n")
print("Receiver started")
while 1:
msg_in = sock.recv(1024)
if not str(msg_in).startswith("[py]" + nick):
if str(msg_in).startswith("/ua"):
print(str(msg_in)[3:])
elif str(msg_in).startswith("/u "):
print(str(msg_in)[2:])
else:
print(str(msg_in[:-1]))
#
if nick == "":
nick = "guest"
print("Name changed to ""guest""")
time.sleep(.5)
thread.start_new_thread(receiver, (server, ))
time.sleep(.5)
thread.start_new_thread(sender())
Connect.py
import socket
import time
class User():
nickel =""
def connect(self, server="xyr.no-ip.info", nick="guest"):
nickel = nick
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server == "":
server="xyr.no-ip.info"
print("server changed to xyr.no-ip.info")
time.sleep(.5)
print("Connecting...")
self.sock.connect((server, 8000))
print("Connected")
time.sleep(.4)
self.sock.send("[py]" + nick + "\n")
self.sock.send(nick + " connected with a python client\n")
print("registered as " + nick)
time.sleep(.3)
def send(self, msg):
self.sock.send(msg + "\n")
def disconnect(self):
self.sock.close()
print("disconnected")
2 个回答
我之前遇到过类似的问题,后来发现一个更简单的解决办法,就是用readchar这个库来获取输入(https://github.com/magmax/python-readchar/tree/master/readchar)。
使用readchar的时候,我会把每次按键的输入存起来(检查按下的是否是退格键和回车键 - 下面有代码片段)。
每次输出的时候,我会在前面加上"/033[1A"(这个是让光标上移),然后打印输出的内容,再加一个"/n"...
在每次输出后,我会把光标移到行首,然后重新打印self.input_buff
里的内容。
这样用户在输入的时候,控制台会显示他们正在输入的内容:
keypress = readkey()
if keypress == key.BACKSPACE:
self.input_buff = self.input_buff[:-1]
print("\033[0A%s " % self.input_buff)
continue
if keypress != key.CR:
self.input_buff = "%s%s" % (self.input_buff, keypress)
print("\033[0A%s" % self.input_buff)
continue
这样就能把输入行保持在底部,而所有的终端输出都在它上面。
我知道这个方法来得有点晚,如果你对curses很在行,也许那是更好的选择...
你的代码把所有内容都写到了标准输出(stdout)上。每当你的发送者或接收者线程有东西到达时,它就会打印到标准输出上。这样做的问题是,由于输出流的基本特性,你无法做到以下几点:
- 把收到的消息放在当前输入/回显内容的上面。
事情发生的顺序是严格按照发生的先后进行的。只要有东西进来,无论光标在哪里,打印语句就会把数据直接输出到那个位置。你不能改变这种行为,除非使用更复杂或更强大的工具。
为了实现你想要的效果,我建议使用 ncurses。你似乎是在Windows上使用Python,所以你需要花点时间去了解如何获得类似的功能。可以看看这个讨论:Windows的Curses替代方案