当前位置:  编程技术>移动开发
本页文章导读:
    ▪跟着教程学习MP3播放器编写,遇到奇怪事,扩展名为MP3、jpg、gif的都可以上载,唯独lrc的上载总失败,终于找到原因        跟着教程学习MP3播放器编写,遇到奇怪事,扩展名为MP3、jpg、gif的都可以下载,唯独lrc的下载总失败,终于找到原因!首先问题描述! 跟着教程学习MP3播放器编写,实现了从自己搭建的服务.........
    ▪ NSThread创设CFRunLoop        NSThread创建CFRunLoop首先是文档对CFRunLoop部分的一个概述,可以帮助我们简单的了解一下CFRunLoop的主要的特性: Overview A CFRunLoop object monitors sources of input to a task and dispatches control when they become re.........
    ▪ Fedora14 基于Qt的UDP传输文字聊天小软件实现 (Qt查询本地Ip、Qt本地时间显示、传输中文汉字实现、Qt的textedit自动滚屏实现、给QPushButton设键盘快捷实现)-续下       Fedora14 基于Qt的UDP传输文字聊天小软件实现 (Qt查询本地Ip、Qt本地时间显示、传输中文汉字实现、Qt的textedit自动滚屏实现、给QPushButton设键盘快捷实现)---续上      先上一张最后运行结果.........

[1]跟着教程学习MP3播放器编写,遇到奇怪事,扩展名为MP3、jpg、gif的都可以上载,唯独lrc的上载总失败,终于找到原因
    来源: 互联网  发布时间: 2014-02-18
跟着教程学习MP3播放器编写,遇到奇怪事,扩展名为MP3、jpg、gif的都可以下载,唯独lrc的下载总失败,终于找到原因!

首先问题描述!
跟着教程学习MP3播放器编写,实现了从自己搭建的服务器下载MP3文件,并播放的功能,但是遇到一个问题,我的下载程序的代码在运行时,下载a01.mp3、a01.jpg、a01.gif、a01.txt等文件都可以正常下载,唯独下载a01.lrc文件时出现异常,下载失败。但如果把a01.lrc文件名改为a01.txt,就可以下载成功,实在找不出问题原因。后来经论坛兄弟帮忙,终于找到解决方法!

代码如下:
负责下载的线程的代码:mp3Name的值赋为01.mp3、a01.jpg、a01.gif、a01.txt等文件都可以正常下载,唯独下载a01.lrc文件时出现异常。

Java code
class DownloadThread implements Runnable { private Mp3Info mp3Info = null; public DownloadThread(Mp3Info mp3Info) { this.mp3Info = mp3Info; } @Override public void run() { // 下载地址http://192.168.1.102/testWeb/歌曲名 // 根据MP3文件的名字,生成下载地址 //String mp3Name = mp3Info.getMp3Name(); //String mp3Name = "a04.lrc"; String mp3Name=""; try { mp3Name = URLEncoder.encode("a04.lrc","UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } String mp3Url = mp3url_head + URLEncoder.encode(mp3Name); // //生成下载文件所用的对象 // HttpDownloader httpDownloader = new HttpDownloader(); // 将文件下载下来,并存储到SDCard中 int result = httpDownloader.downFile(mp3Url, mp3Path, URLEncoder.encode(mp3Name)); String resultMessage = null; if (result == -1) { resultMessage = mp3Name + "下载失败"; cancelled = true; } else if (result == 1) { resultMessage = mp3Name + "已存在,无需重复下载"; cancelled = true; } else if (result == 0) { resultMessage = mp3Name + "下载成功"; } // 发送特定action的广播 Intent Broadcastintent = new Intent(); Broadcastintent.setAction("android.intent.action.MY_RECEIVER"); Broadcastintent.putExtra("resultMessage", resultMessage); sendBroadcast(Broadcastintent); } }


 httpDownloader.downFile代码
Java code
/** * 该函数返回整形 -1:代表下载文件出错 0:代表下载文件成功 1:代表文件已经存在 */ public int downFile(String urlStr, String path, String fileName) { InputStream inputStream = null; try { if (fileUtils.isFileExist(fileName, path)) { return 1; } else { inputStream = getInputStreamFromUrl(/blog_article/urlStr/index.html); File resultFile = fileUtils.write2SDFromInput(path, fileName, inputStream); if (resultFile == null) { return -1; } } } catch (Exception e) { e.printStackTrace(); return -1; } finally { try { inputStream.close(); } catch (Exception e) { e.printStackTrace(); } } return 0; }


getInputStreamFromUrl代码
Java code
public InputStream getInputStreamFromUrl(/blog_article/String urlStr/index.html) throws MalformedURLException, IOException { url = new URL(urlStr); HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); urlConn.setRequestMethod("GET"); InputStream inputStream = urlConn.getInputStream(); this.lenghtOfFile = urlConn.getContentLength(); return inputStream; }


fileUtils.write2SDFromInput代码
Java code
/** * 将一个InputStream里面的数据写入到SD卡中 */ public File write2SDFromInput(String path, String fileName, InputStream input) { File file = null; OutputStream output = null; try { creatSDDir(path); file = createFileInSDCard(fileName, path); output = new FileOutputStream(file); byte buffer[] = new byte[4 * 1024]; int temp; while ((temp = input.read(buffer)) != -1) { this.total += temp;// total = total + temp output.write(buffer, 0, temp); } output.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { output.close(); } catch (Exception e) { e.printStackTrace(); } } return file; }


异常情况:

08-01 09:24:37.934: W/System.err(7773): java.io.FileNotFoundException: http://192.168.1.100/testWeb/a04.lrc
08-01 09:24:37.934: W/System.err(7773): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1162)
08-01 09:24:37.944: W/System.err(7773): at hk.download.HttpDownloader.getInputStreamFromUrl(HttpDownloader.java:108)
08-01 09:24:37.944: W/System.err(7773): at hk.download.HttpDownloader.downFile(HttpDownloader.java:75)
08-01 09:24:37.954: W/System.err(7773): at hk.mp3player.service.DownloadService$DownloadThread.run(DownloadService.java:175)
08-01 09:24:37.954: W/System.err(7773): at java.lang.Thread.run(Thread.java:1096)
08-01 09:24:37.954: W/System.err(7773): java.lang.NullPointerException
08-01 09:24:37.954: W/System.err(7773): at hk.download.HttpDownloader.downFile(HttpDownloader.java:87)
08-01 09:24:37.954: W/System.err(7773): at hk.mp3player.service.DownloadService$DownloadThread.run(DownloadService.java:175)
08-01 09:24:37.964: W/System.err(7773): at java.lang.Thread.run(Thread.java:1096)
08-01 09:24:38.004: W/System.err(7773): java.io.FileNotFoundException: http://192.168.1.100/testWeb/a03.lrc
08-01 09:24:38.004: W/System.err(7773): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1162)
08-01 09:24:38.014: W/System.err(7773): at hk.download.HttpDownloader.getInputStreamFromUrl(HttpDownloader.java:108)
08-01 09:24:38.014: W/System.err(7773): at hk.download.HttpDownloader.downFile(HttpDownloader.java:75)
08-01 09:24:38.014: W/System.err(7773): at hk.mp3player.service.DownloadService$DownloadlrcThread.run(DownloadService.java:215)
08-01 09:24:38.014: W/System.err(7773): at java.lang.Thread.run(Thread.java:1096)
08-01 09:24:38.014: W/System.err(7773): java.lang.NullPointerException
08-01 09:24:38.064: W/System.err(7773): at hk.download.HttpDownloader.downFile(HttpDownloader.java:87)
08-01 09:24:38.064: W/System.err(7773): at hk.mp3player.service.DownloadService$DownloadlrcThread.run(DownloadService.java:215)
08-01 09:24:38.064: W/System.err(7773): at java.lang.Thread.run(Thread.java:1096)

解决方法!!

Win7 在IIS中增加MIME类型文件,步骤如下:

第一步:开始 ->  所有程序 -> 管理工具 -> Internet 信息服务(IIS)管理器

第二步:点击“MIME”类型:

第三步:在上图右侧有一个“添加”按钮,如下图:

第四步:填写MIME设置,例如添加.lrc文件,如下图:



    
[2] NSThread创设CFRunLoop
    来源: 互联网  发布时间: 2014-02-18
NSThread创建CFRunLoop

首先是文档对CFRunLoop部分的一个概述,可以帮助我们简单的了解一下CFRunLoop的主要的特性:

Overview

A CFRunLoop object monitors sources of input to a task and dispatches control when they become ready for processing. Examples of input sources might include user input devices, network connections, periodic or time-delayed events, and asynchronous callbacks.

Three types of objects can be monitored by a run loop: sources (CFRunLoopSource Reference), timers (CFRunLoopTimer Reference), and observers (CFRunLoopObserver Reference). To receive callbacks when these objects need processing, you must first place these objects into a run loop withCFRunLoopAddSource,CFRunLoopAddTimer, orCFRunLoopAddObserver. You can later remove an object from the run loop (or invalidate it) to stop receiving its callback.

Each source, timer, and observer added to a run loop must be associated with one or more run loop modes. Modes determine what events are processed by the run loop during a given iteration. Each time the run loop executes, it does so in a specific mode. While in that mode, the run loop processes only the events associated with sources, timers, and observers associated with that mode. You assign most sources to the default run loop mode (designated by thekCFRunLoopDefaultMode constant), which is used to process events when the application (or thread) is idle. However, the system defines other modes and may execute the run loop in those other modes to limit which sources, timers, and observers are processed. Because run-loop modes are simply specified as strings, you can also define your own custom modes to limit the processing of events

Core Foundation defines a special pseudo-mode, called the common modes, that allow you to associate more than one mode with a given source, timer, or observer. To specify the common modes, use thekCFRunLoopCommonModes constant for the mode when configuring the object. Each run loop has its own independent set of common modes and the default mode (kCFRunLoopDefaultMode) is always a member of the set. To add a mode to the set of common modes, use theCFRunLoopAddCommonMode function.

There is exactly one run loop per thread. You neither create nor destroy a thread’s run loop. Core Foundation automatically creates it for you as needed. You obtain the current thread’s run loop withCFRunLoopGetCurrent. Call CFRunLoopRun to run the current thread’s run loop in the default mode until the run loop is stopped withCFRunLoopStop. You can also callCFRunLoopRunInMode to run the current thread’s run loop in a specified mode for a set period of time (or until the run loop is stopped). A run loop can only run if the requested mode has at least one source or timer to monitor.

Run loops can be run recursively. You can call CFRunLoopRun orCFRunLoopRunInMode from within any run loop callout and create nested run loop activations on the current thread’s call stack. You are not restricted in which modes you can run from within a callout. You can create another run loop activation running in any available run loop mode, including any modes already running higher in the call stack.

Cocoa applications build upon CFRunLoop to implement their own higher-level event loop. When writing an application, you can add your sources, timers, and observers to their run loop objects and modes. Your objects will then get monitored as part of the regular application event loop. Use the getCFRunLoop method of NSRunLoop to obtain the correspondingCFRunLoopRef type. In Carbon applications, use theGetCFRunLoopFromEventLoop function.

For more information about how run loops behave, see “Run Loops” in Threading Programming Guide.

大致的翻译:

CFRunLoop对象监控任务(task)的输入源,并在它们为处理做好准备的时候调度控制。输入源样例可能包括用户输入设备、网络链接、定期或时间延迟事件,还有异步回调。 

有3类对象可以被run loop监控:sources、timers、observers。

当这些对象需要处理的时候,为了接收回调,首先必须通过 CFRunLoopAddSource,CFRunLoopAddTimer ,or CFRunLoopAddObserver把这些对象放入run loop。 要停止接收它的回调,你也可以稍候通过CFRunLoopRemoveSource从runloop中移除某个对象。 

run loop有不同的运行模式,每种模式都有其自身的对象集,runloop监控,同时在该模式下运行。 CoreFoundation定义了一种默认模式kCFRunLoopDefaultMode来持有对象,在应用或线程闲置的时候这些对象应该被监控。当一个对象被添加到不认识的模式时,额外模式自动创建。每个runloop有它自己独立的模式集。

Core Foundation还定义了一个特殊的伪模式kCFRunLoopCommonModes来持有应当被“common”模式集共享的对象。 通过调用CFRunLoopAddCommonMode来添加一个模式到“common”模式集。 默认模式kCFRunLoopDefaultMode 总是common模式集中的一个成员。kCFRunLoopCommonModes 常数决不会传给CFRunLoopRunInMode 。每个runloop有它自己独立的common模式集。

每个线程恰好有一个run loop,既不可以创建,也不能销毁线程的run loop。,Core Foundation根据需要为你创建。通过CFRunLoopGetMain  你可以获得当前线程的runloop。调用lCFRunLoopRun 来使当前线程的run loop以默认模式运行起来,直到调用CFRunLoopStop 来停止runloop。你也可以调用CFRunLoopRunInMode 来使当前线程的runloop以指定模式运行起来一段时间或者直到run loop被停止。 runloop只能在请求模式至少有一个source或者timer可监控的情况下运行起来。 

run loop可以递归运行,你可以在任何run loop标注内部调用CFRunLoopRun 或 CFRunLoopRunInMode,还可以创建嵌套run loop,并在当前线程调用栈激活,在标注内并没有限制在那种模式可以运行。 你可以创建另一个runloop,激活运行在任何可行的run loop模式,包括任何已经运行在调用堆栈中的更高的模式。

Cocoa 和 Carbon 每个都是建立在 CFRunLoop上来实现它们自己更高级别的事件循环。当编写一个 Cocoa 或者 Carbon应用,你可以添加你的sources、timer和observers到它们的runloop对象中。你的对象将会作为常规应用事件循环的一部分来得到监控。使用 NSRunLoop实例方法 getCFRunLoop  来获得对应应于cocoa runloop的CFRunLoop,在carbon应用中使用 GetCFRunLoopFromEventLoop 函数 


例子1,在NSThread创建Run Loop:

IPhone多线程编程提议用NSOperation和NSOperationQueue,这个接口苹果已经封装的很具有自动化的效果,对开发者来说,更简单易用。

但是有些情况下,我们还是在运行一些长线任务或者复杂任务的时候,还是需要用到NSThread,这就需要为NSThread创建一个run loop. 

//创建一个新的线程,其中object:nil部分可以作为selector的参数传递,在这里没有参数,设为nil
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(playerThread: ) object:nil];

//开启线程,如果是利用NSOperation,只需要加入到NSOperationQueue里面去就好了,queue自己会在合适的时机执行线程,而不需要程序员自己去控制。
[thread start]; 

- (void) playerThread:id)unused 
{ 
    currentLoop = CFRunLoopGetCurrent();//子线程的runloop引用 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];//为子线程创建自动释放池 
    //run loop 
    [self initPlayer];
    //CFRunLoopRun,Runs the current thread’s CFRunLoop object in its default mode indefinitely. 
    CFRunLoopRun(); 
    //run loop,这里就会停住了。 
    [pool release]; 
} 
// 实现一个timer,用于检查子线程的工作状态,并在合适的时候做任务切换。或者是合适的时候停掉
// 自己的run loop
-(void) initPlayer 
{ 
    // 在这里你可以初始化一个工作类,比如声音或者视频播放 
    NSTimer *stateChange = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self
                                                          selector:@selector(checkState:) userInfo:nil repeats:YES]; 
} 
-(void) checkState:(NSTimer*) timer 
{ 
    if(需要退出自定义的线程了) 
    { 
        //释放子线程里面的资源
        //释放资源的代码....
        /*结束子线程任务 CFRunLoopStop,This function forces rl to stop running and 
        return control to the function that called CFRunLoopRun or CFRunLoopRunInMode 
        for the current run loop activation. If the run loop is nested with a callout
        from one activation starting another activation running, only the innermost
        activation is exited.*/
        CFRunLoopStop(currentLoop); 
    } 
}


例子2,用Run Loop控制动画的过程: 

#import "UIView-ModalAnimationHelper.h"

@interface UIViewDelegate : NSObject
{
	CFRunLoopRef currentLoop;
}
@end

@implementation UIViewDelegate
-(id) initWithRunLoop: (CFRunLoopRef)runLoop 
{
	if (self = [super init]) currentLoop = runLoop;
	return self;
}

-(void) animationFinished: (id) sender
{
	CFRunLoopStop(currentLoop);
}
@end

@implementation UIView (ModalAnimationHelper)
+ (void) commitModalAnimations
{
	CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
	
	UIViewDelegate *uivdelegate = [[UIViewDelegate alloc] initWithRunLoop:currentLoop];
	[UIView setAnimationDelegate:uivdelegate];
	[UIView setAnimationDidStopSelector:@selector(animationFinished:)];
	[UIView commitAnimations];
	CFRunLoopRun();
	[uivdelegate release];
}
@end


//应用

[UIView beginAnimations:nil context:UIGraphicsGetCurrentContext()];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.4f];
......
[UIView commitModalAnimations];






    
[3] Fedora14 基于Qt的UDP传输文字聊天小软件实现 (Qt查询本地Ip、Qt本地时间显示、传输中文汉字实现、Qt的textedit自动滚屏实现、给QPushButton设键盘快捷实现)-续下
    来源: 互联网  发布时间: 2014-02-18
Fedora14 基于Qt的UDP传输文字聊天小软件实现 (Qt查询本地Ip、Qt本地时间显示、传输中文汉字实现、Qt的textedit自动滚屏实现、给QPushButton设键盘快捷实现)---续上

      先上一张最后运行结果图,顺便说下开发环境:fedora14+qt4.8.1.界面的搭建是用designer画的,以前还没用过,都用程序写界面发现吃力不讨好,用designer画的效果和程序写时完全等价的。他会自动生成一个类似android下的xml布局文件,并且自动关联槽函数,不用白不用,哈哈!基类为widget。

先交代几个重要变量:

192.168.2.211        对应变量 ipEdit

6665         ------------------------portEdit

信息交互栏下面的编辑框------getEdit

发送信息下面的编辑框--------sendEdit

另外几个按钮就不多说了!

        I、 widget.h的代码:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetwork/QUdpSocket>
#include<QtNetwork/QHostAddress>
#include <QMessageBox>
#include <QHostInfo>
#include <QNetworkInterface>

 

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT
   
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    QHostAddress *localHostAddr;
     QHostAddress *remoteHostAddr;
    QString localIpStr;
    QString remoteIpStr;

    QString getIp();
    void autoScroll();

private slots:
    void send();
    void receive();    
    void on_clearButton_clicked();
    void on_configButton_clicked();

    void on_exitButton_clicked();

private:
    Ui::Widget *ui;
    QUdpSocket *udpSocket1;  
    bool configFlag;
};

#endif // WIDGET_H

         II、 widget.cpp里的核心代码及说明:

首先初始化如下: ui->setupUi(this);
    configFlag = false;        //初始化连接参数 为未连接
    ui->getTextEdit->ensureCursorVisible();
    ui->sendTextEdit->setFocus();      //程序启动时,焦点停在发送对话框
    ui->ipEdit->setText("192.168.2.211");   //设置默认的远程端Ip
    ui->portEdit->setText("6665");           //设置默认端口号

一、快捷键设置:

 ui->udpSendButton->setShortcut(tr("Alt+F"));  

这点重点说下,不知道为什么想用Ctrl+Enter,但用不了,用其他快捷键就可以,这里用Alt+F。

二、本地Ip的查找

       这块是最曲折的。最初是用

//    QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName());
//    hostaddr1 = info.addresses().takeFirst();

这样查询出的hostaddr1其实是本地回环Ip地址, hostaddrStr = hostaddr1.toString();,可以用qDebug()<<hostaddrStr打印一下,发现结果是127.0.0.1.并不是真正的本地Ip地址。localHostAddr = new QHostAddress(localIpStr);如果这里用new QhostAddrress(hostaddr1),用这个地址的话可以自己给自己发,但和局域网其他机器通讯时是根本不可能的。

这里提供一下查询本地Ip的函数:

QString Widget::getIp()
{
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    foreach (QHostAddress address, list)
    {
        if(address.protocol() == QAbstractSocket::IPv4Protocol)   //我们使用IPv4地址
        {
            if(address.toString().contains("127.0."))
                continue;
            qDebug()<<"本机Ip:"<<address.toString();
            return address.toString();
        }
    }
    return 0;

}

只有这个函数,打印出来的Ip地址才是你机器上真正的Ip。

所以我们

 localIpStr = getIp();

 localHostAddr = new QHostAddress(localIpStr);

首先获得本地Ip地址,用这个Ip地址也初始化QHostAddress变量。这是我们的本地Ip.

    udpSocket1 = new QUdpSocket(this);
    bool bindFlag = udpSocket1->bind(*localHostAddr, 6665, QUdpSocket::ShareAddress);

上面是初始化一个udpsocket,将他和本地Ip及 开放的端口号绑定在一起。

接下来判断绑定失败与否:

 if(!bindFlag)
    {
        QMessageBox box;
        box.setText(tr("初始化绑定socket错误!"));
        box.exec();
    }
    else
    {
        connect(udpSocket1, SIGNAL(readyRead()), this, SLOT(receive()));
        connect(ui->udpSendButton, SIGNAL(clicked()), this, SLOT(send()));
    }

绑定成功了,就连接槽函数,第一个receive()是udpSocket1在接收到数据时触发的,第二个send()是当按下发送按键时,往对端机器发信息的。接收数据和发送数据时同一个Socket!大家注意了,网上其他人用一个socket接收,一个socket发送。可能也可以把,这里用一个。

  this->setWindowTitle(tr("基于Qt的UDP聊天界面-------顶礼准提佛母")); 设置标题。

       (顶礼准提佛母,顶礼南师怀瑾,希望大家少杀生少吃肉,孝敬父母,多多贡献源码:

 南怀瑾老师传承的准提心咒:http://user.qzone.qq.com/707798286/blog/1341824452,

              南怀瑾老师念诵准提咒100遍30分钟版本:ttp://www.tudou.com/programs/view/7eqpbQ7O8UQ/               

            南怀瑾老师2002年香港准提法开示:http://wenku.baidu.com/view/f86c34d7195f312b3169a577.html

           南怀瑾老师教念的准提咒:           http://wenku.baidu.com/view/6369277f168884868762d673.html

          金刚上师南公怀瑾传授准提法修持要领开示(1978年9月):           http://wenku.baidu.com/view/c5f1c14fc850ad02de804153.html)

    南师慈悲叮咛:持准提咒容易疏忽之处:http://www.xuefo.net/nr/article10/103024.html

                                                                                    -------------不喜欢的敬请绕过。

三、发送数据的槽函数-----解决发送中文乱码的关键

 

void Widget::send()
{
    autoScroll();
    QString sendStr = ui->sendTextEdit->toPlainText();
    QByteArray sendByteArray = sendStr.toAscii();
    QMessageBox box;
    if(sendStr.length()==0)
    {
        box.setText(tr("请输入发送内容"));
        box.exec();
    }
    else if(configFlag)
    {

        udpSocket1->writeDatagram(sendByteArray, sendByteArray.length(), *remoteHostAddr, 6665);

        //本地发送信息再信息交互窗口的显示
        QDateTime time;
        QString timeStr = time.currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
        ui->getTextEdit->setTextColor(QColor("red"));
        ui->getTextEdit->insertPlainText("本机" + localIpStr + ": " + timeStr + "\n");
        ui->getTextEdit->setTextColor(QColor("black"));
        ui->getTextEdit->insertPlainText( sendStr +"\n");
        ui->sendTextEdit->clear();          //点击发送后,发送编辑框内清零
        ui->sendTextEdit->setFocus();      //焦点停留在发送编辑框
    }
    else if(!configFlag)
    {
        box.setText("请您先点击确认按钮!");
        box.exec();
    }
}

           这里有几点说说:

 1,发送数据的实现

          QString sendStr = ui->sendTextEdit->toPlainText();
          QByteArray sendByteArray = sendStr.toAscii();
         udpSocket1->writeDatagram(sendByteArray, sendByteArray.length(), *remoteHostAddr, 6665);

          能否正确显示中文就在这一句,必须把QString转成QByteArray再发送,接收端有好几种实现方法,但发送端不这么搞的话,就解析不了中文。这块让我搞了一整天!

2,本地时间显示

       QDateTime time;
        QString timeStr = time.currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd"); 要包含一个头文件,#include <qdatetime.h>,奇怪的是这个头文件包含在widget.h里就不行,非要搞到widget.cpp里才中。

3,显示文本的时候  ui->getTextEdit->insertPlainText( sendStr +"\n");
        ui->sendTextEdit->clear();          //点击发送后,发送编辑框内清零
        ui->sendTextEdit->setFocus();      //焦点停留在发送编辑框

一定要搞成insertPlainText,如果搞成setText,就会把显示窗口搞成只有一句话,这个函数是不销毁以前的内容,插入在以前的文本内容之后的函数。

4,自动滚屏的实现,函数实现为:

void Widget::autoScroll()
{
    QTextCursor cursor = ui->getTextEdit->textCursor();
    cursor.movePosition(QTextCursor::End);
    ui->getTextEdit->setTextCursor(cursor);
}

     这里插一句,getEdit,的属性里设成enables,read Only,在designer里,点控件,设置属性里这么设置。如果不设自动滚屏是什么效果呢??

         只有拖动右边滚动鼠标才能显示,所以一定要设自动滚屏。而且在两个地方,一个是receive里调用这个函数,有东西显示的时候,滚屏到最后显示! 点发送的时候,也要调用这个滚屏函数,如果您聊天的时候,把光标停留在信息交互栏里某个位置A,下一条信息就会显示在A光标后,而不是我们希望的每次都挨着上一条信息后显示。所以点发送按钮后,要先调用,目的在此!

四、接收槽函数的实现

 

 void Widget::receive()
{
    while(udpSocket1->hasPendingDatagrams())
    {
        QTextCodec *tc=QTextCodec::codecForName("UTF-8"); //UTF-8
        QDateTime time;
        QString timeStr = time.currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");

        QByteArray data;
        data.resize(udpSocket1->pendingDatagramSize());
        udpSocket1->readDatagram(data.data(), data.size());
//        QString dataStr =  QString::fromUtf8(data.data());   //这样写也是正确的
        QString dataStr = tc->toUnicode(data);
        ui->getTextEdit->setTextColor(QColor("red"));
        ui->getTextEdit->insertPlainText("远程"  + remoteIpStr+": "+ timeStr +"\n" );
        ui->getTextEdit->setTextColor(QColor("black"));
        ui->getTextEdit->insertPlainText(dataStr  + "\n" );
        autoScroll();

    }

}

      为了显示中文,关键在三句

     QTextCodec *tc=QTextCodec::codecForName("UTF-8");

     QString dataStr = tc->toUnicode(data);
如果不写这两句,用这句也可以实现:QString dataStr =  QString::fromUtf8(data.data());  

五,点确定按钮的槽函数:

void Widget::on_configButton_clicked()
{
     remoteIpStr = ui->ipEdit->text();
    QString port = ui->portEdit->text();
    qDebug()<<"远程端Ip:"<<remoteIpStr<<"端口号:"<<port;
    remoteHostAddr = new QHostAddress(remoteIpStr);

    QMessageBox box;
    if(remoteIpStr.length()==0 || port.length()==0 || port.toInt()<1024)
    {
        configFlag = false;
        box.setText("请正确设置远程端Ip地址和端口号!");
        box.exec();
    }
    else
    {
        configFlag = true;
        box.setText("您设置的远程端Ip:" + remoteIpStr+"端口号:"+port);
        box.exec();
    }

}

用来初始化远程Ip地址!

至此唯一不完美的是,如何为qt编写的程序添加一个图标?下午搞了一会,没有成功!网上貌似说的都是在windows下,我要再linux下。哪位大神实现了指点一下后学。

源码下载:http://download.csdn.net/detail/yanzi1225627/4475122

 


    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android提高之自定义Menu(TabMenu)实现方法 iis7站长之家
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3