用Qt编写一个类似于QQ的聊天软件,聊天记录过程是用qwebview cookie加载的,我想实现一个右键弹出菜单的功能

QT,我正在用QTcreator写一个类似QQ的聊天工具,其中涉及到好友列表_百度知道
QT,我正在用QTcreator写一个类似QQ的聊天工具,其中涉及到好友列表
我有想过自己定义一个类myTreeItem。请高手们教我!,只是多一个bool型状态成员_isopened,不胜感激,没办法进行下一步操作,继承自QTreeWidgetItem,int)---也就是说我双击一个好友得到该好友item的指针始终是QTreeWidgetItem*而不是我自定义的myTreeItem*,但是双击好友名字时发出的信号始终是itemDoubleClicked(QTreeWidgetItem*我如何做到多次点击打开某个好友而不会重复弹出聊天框!
提问者采纳
Close&然后再双击的时候就判断那个Item的第一个Text的值,item-&);OPEN&quot。我想这个思路应该可行;setText(1,查看是否为close,那么,你的好友列表既然是treeWidgetI,有问题再补充,是的话就打开对话框,&quot我有个思路,当你打开聊天对话框的时候你就给对应的好友所在的Item设置一下;关闭对话框的时候设置为&quot,不是的话就不打开
提问者评价
谢谢,已经完成了
其他类似问题
为您推荐:
聊天工具的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁当前访客身份:游客 [
当前位置:
最近在写IM 聊天界面,想设计出一个类似QQ气泡聊天的样式&使用了几种办法
1:使用Qt下面的QListview来实现QQ类似效果,差强人意
2:使用QWebview加载html css样式来完成,发现效果不错,但是毕竟webview占用巨大的内存
3:使用QTextBrower加载css,但是好像只支持css2.1版本,css3完全不支持,这样的话,花哨的样式应该是无法实现
基于以上三种思路
& & 最后发现还是QML实现比较好,但是qml基于文本与动画图片混合显示没找到好的办法,有好的办法的希望可以给指点一二
目前写了第一种办法的效果,但是delegate没法实现文本复制等操作,可能会放弃之
求各位大神有更好的点子指点一二
共有8个答案
<span class="a_vote_num" id="a_vote_num_
我现在也要实现类似的功能,两个月过去了,你有什么建议呢?
--- 共有 1 条评论 ---
没有好的解决方案,使用QML倒是可以达到一定的效果,不理想
(10个月前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
点9 图就可以破之了阿?
<span class="a_vote_num" id="a_vote_num_
如果硬是要QWidget或者graphicview来实现的话,qml现在还不是很好使用
<span class="a_vote_num" id="a_vote_num_
QML应该能解决的、、
<span class="a_vote_num" id="a_vote_num_
用Qt的话,qml是最好的选择,没有之一
<span class="a_vote_num" id="a_vote_num_
没有人来说说思路吗?有人提到使用graphicview框架,个人正在尝试呢
<span class="a_vote_num" id="a_vote_num_
我们服务器端使用的是nodejs来处理即时信息,外加部分php接口内容
<span class="a_vote_num" id="a_vote_num_
呀,我也在做一个IM,客户端用的PyQt。你服务端用的什么网络模型。
有什么技术问题吗?
toby520...的其他问题
类似的话题ASP.NET怎么实现根据ID号或用户名虚拟出一个访问路径来_qt,c++ 内嵌简单map 怎么实现_各位前辈,小弟我在用ado方式和sql数据库联接的时候总是出现第一行:“=”附近有复发异常,请帮忙看一下多谢啦__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
ASP.NET怎么实现根据ID号或用户名虚拟出一个访问路径来
qt,c++ 内嵌简单map 怎么实现
各位前辈,小弟我在用ado方式和sql数据库联接的时候总是出现第一行:“=”附近有复发异常,请帮忙看一下多谢啦
ASP.NET怎么实现根据ID号或用户名虚拟出一个访问路径来
ASP.NET如何实现根据ID号或用户名虚拟出一个访问路径来?ASP.NET如何实现根据ID号或用户名虚拟出一个访问路径来?
比如我要做一个博客系统,在网站根目录下有一个目录Blog,在其下面有一个文件Default.aspx,此文件即是用来根据用户的ID号来读取用户博客首页的信息的,假设网站的域名为,那么通常我们会这样来访问用户博客首页的信息:
/Blog/Default.aspx?ID=nnn(nnn为用户ID号)
但是以之种方式来访问对于用户来说不易记住地址,也没有直观性,我想换成另一种方式,即:
/Blog/nnn/Default.html
/Blog/nnn/index.html
请问这种方式如何能实现呢?
以前我见到过能类似情况的例子的,好像是在IIS里进行设置的,但具体怎么做不清楚。
希望有高手指点一下,谢谢!!------解决方案--------------------搜索URL重写
------解决方案--------------------google/baidu UrlRewrite
------解决方案--------------------URLRewrite很容易搞定 配置IIS和WebConfig 把URLRewrite.dll放到Bin目录下
------解决方案--------------------/china/msdn/library/webservices/asp.net/URLRewriting.mspx?mfr=true
------解决方案--------------------url重写 httpmodule
qt,c++ 内嵌简单map 怎么实现
qt,c++ 内嵌简单地图 如何实现?目前我想到的是内嵌一个网页:
一个网页,显示一个中国地图,不需要像谷歌地图显示那么多路线,那么精细,我只想最多显示到 省、市,然后 给省、市画出轮廓就可以了,然后我想在对应城市轮廓上显示对应的一小段文字,文字动态显示,3秒后自动消失,请问下 有什么实现方法不,我尝试用百度地图弄,不过觉得好没有头绪,好无助啊,求大神帮忙
还有别的办法么,能给点详细的资料么
------解决方案--------------------需求简单的话,载入一张中国地图图片就好了。
复杂一点的话,Qt例子中好像有一个可以满足要求。------解决方案--------------------qt 里面有qwebview..。。直接Load?..------解决方案--------------------直接显示网页....------解决方案--------------------http://blog.csdn.net/tju355/article/details/7676568------解决方案--------------------自己写个HTML文件,里面显示百度地图,然后里面写一些Javascript函数来调用百度地图API对地图进行操作,QT方面用QWebview来显示HTML文件,调用Javascript函数来实现各种不同的功能。
各位前辈,小弟我在用ado方式和sql数据库联接的时候总是出现第一行:“=”附近有复发异常,请帮忙看一下多谢啦
各位前辈,我在用ado方式和sql数据库联接的时候总是出现第一行:“=”附近有复发错误,请帮忙看一下谢谢啦。下面这是我做的登陆模块,因为总是出现“=”附近有语法错误,一直没办法和数据库连上,请各位前辈高手帮忙解答,谢谢。
cmdok_Click()
errhandler
ADODB.Connection
gconn.Open
"Provider=MSDASQL.1;Persist
Info=FUser
Source=Initial
Catalog=ec "
gnusertype
cbousertype.ListIndex
gsusername
'&user& " 'and
用户密码 " '&pwd& " 'and
用户类型= "&gnusertype
ADODB.Recordset
adOpenStatic
"次用户不存在或密码错误清重新输入! ",
vbCritical,
"输入错误 "
txtuser.SetFocus
txtuser.SelStart
txtuser.SelLength
Len(txtuser)
"输入错误次数过多无权访问本系统! ",
vbCritical,
gconn.Close
frmmain.Show
errhandler:
Err.Description,
vbCritical,
Sub------解决方案--------------------strsql =
"select * from userlist where 用户名= ' " & user & " 'and 用户密码= ' "& pwd & " ' and 用户类型= "& gnusertype &
" " ------解决方案--------------------strsql =
"select * from userlist where 用户名= "
'&user& " 'and 用户密码 " '&pwd& " 'and 用户类型= "&gnusertype 錯了
"select * from userlist where 用户名= "
'& user & " 'and 用户密码=
" '& pwd &
" 'and 用户类型=
"& gnusertype
------解决方案--------------------数据库中没有userlist这个表
如果您喜欢IT行业或者对IT行业感兴趣,想开拓技术视野,欢迎加入本站官方QQ群:,在群里认识新朋友和交流技术^_^
本站联系邮箱:  在上2次文章&&
&中已经初步介绍了群聊功能和文件传输功能,这一节中主要在这个基础上加入一个私聊功能。
  参考文献依旧是:《Qt及Qt Quick开发实战精解》一书中的第5个例子以及 网站上的源码。另外这次的私聊功能也是参考网友的,他的程序有些bug,其中最严重的bug是当私聊第二次聊天的时候对方会接收不到信息。这次主要是将这个bug和其它一些小bug修补了,但是仍然有一个漏洞就是:当第二次私聊时,后面那个的发送方收到信息的时候有可能会多一个窗口弹出来。目前还找不到其原因。猜想是:在第一次聊天接收时关闭聊天窗口后,其内存没有释放。但是当窗口关闭时我们觉得其内存释放应该在Qt内部自己实现。
& & &下面来讲一下私聊发送端和接收端具体实现过程。
& & &发送端流程图如下:
  接收端的流程图如下:
  下面来介绍下2者实现的具体过程:
  A方(主动开始首次发送的一方):
在主窗口右侧双击自己想与之聊天的B方,此时A方实际上完成的工作有:用B方的主机名和ip地址新建了私聊的类privatechat,在新建该类的过程中,已经设置了显示顶端为:与***聊天中,对方IP:***,且绑定了本地ip和私聊的专用端口,同时设置了信号与槽的联系,即该端口如果有数据输入,则触发槽函数processPendingDatagrams().该函数是char.cpp中的。
当上面的新建私聊类完成后,用通讯对方ip地址和其群聊专用的端口(但用的是主udp群聊的socket进行的)将以下内容分别发送出去:消息类型(Xchat),用户名,主机名,本地ip地址。完成后,在屏幕中显示私聊窗口。
在私聊窗口中输入需要聊天的内容,单击发送键。该过程玩成的内容有:分别将消息类型(Message)&#43;用户名&#43;本地名&#43;本地IP&#43;消息内容本身通过私聊专用端口发送出去。在私聊窗口中显示主机名&#43;聊天时间,换行后显示消息内容本身。
  B方(第一次信息是他人发送过来的):
当A在2步骤中用群聊的方法发送其消息类型(Xchat),其用户名,其主机名,其ip地址后,由于程序运行时已经初始化了widget.cpp中的构造函数,所以每个程序都绑定了本地地址&#43;群聊专用的端口,一旦有数据传入,就触发widget.cpp中的槽函数processPendingDatagrams().
在processPendingDatagrams()函数中,判断消息类型为Xchat后,接收缓存区内接收对方用户名,对方主机名和对方ip地址。并用接收到的主机名和ip地址新建一个私聊类。新建该私聊的过程与A中的步骤1一样。完后在程序中显示私聊窗口。
当对方A按完发送按钮后,通过私聊专用端口绑定槽函数来触发chart.cpp中的processPendingDatagrams()函数,该函数中先读取消息类型(Message),然后依次读取用户名,主机名,ip地址,消息内容本身,并将对方信息和消息内容显示在聊天窗口中。
  实验结果如下:
  群聊界面:
  私聊界面:
  文件传输过程截图:
  实验总结(下面几点只是暂时的理解):
使用类时,如果直接用构造函数定义该类的对象,则定义该类的函数接收时,该对象的生命也就结束了,所以如果要在其他函数中定义一个类的对象时并长久使用,可以使用new定义一个对象的初始指针。这样就在内存中永存了。
如果某个窗口类需要显示时直接调用其指针-&show()或者其对象-.show(),这个函数只是将内存中该类的对象显示出来而已(因为与界面有关),并不是重新建一个类对象。其表示该类的界面等可以显示,所以一旦show过即使改变了界面的内容,后面也无需一直调用show函数,界面会自动显示的。
当关闭某个窗口时,只是将其隐藏,并没有释放其内存。
程序源码:
 widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include &QWidget&
#include &QtNetwork&
#include &QtGui&
#include &tcpclient.h&
#include &tcpserver.h&
#include &chat.h&
using namespace std::tr1;
namespace Ui {
//enum MessageType
NewParticipant,
ParticipantLeft,
//枚举变量标志信息的类型,分别为消息,新用户加入,和用户退出
class Widget : public QWidget
explicit Widget(QWidget *parent = 0);
~Widget();
QString getUserName();
QString getMessage();
chat* privatechat1;
protected:
void changeEvent(QEvent *e);
void sendMessage(MessageType type,QString serverAddress=&&);
void newParticipant(QString userName,QString localHostName,QString ipAddress);
void participantLeft(QString userName,QString localHostName,QString time);
void closeEvent(QCloseEvent *);
void hasPendingFile(QString userName,QString serverAddress,
QString clientAddress,QString fileName);
bool eventFilter(QObject *target, QEvent *event);//事件过滤器
Ui::Widget *
QUdpSocket *udpS
QString fileN
TcpServer *
QString getIP();
bool saveFile(const QString& fileName);//保存聊天记录
void showxchat(QString name, QString ip);
private slots:
void on_tableWidget_doubleClicked(QModelIndex index);
void on_textUnderline_clicked(bool checked);
void on_clear_clicked();
void on_save_clicked();
void on_textcolor_clicked();
void on_textitalic_clicked(bool checked);
void on_textbold_clicked(bool checked);
void on_fontComboBox_currentFontChanged(QFont f);
void on_fontsizecomboBox_currentIndexChanged(QString );
void on_close_clicked();
void on_sendfile_clicked();
void on_send_clicked();
void processPendingDatagrams();
void sentFileName(QString);
void currentFormatChanged(const QTextCharFormat &format);
#endif // WIDGET_H
widget.cpp:
#include &widget.h&
#include &ui_widget.h&
using namespace std::tr1;
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
ui-&setupUi(this);
this-&resize(850,550);
ui-&textEdit-&setFocusPolicy(Qt::StrongFocus);
ui-&textBrowser-&setFocusPolicy(Qt::NoFocus);
ui-&textEdit-&setFocus();
ui-&textEdit-&installEventFilter(this);//设置完后自动调用其eventFilter函数
privatechat = NULL;
privatechat1 = NULL;
udpSocket = new QUdpSocket(this);
port = 45454;
udpSocket-&bind(port,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
sendMessage(NewParticipant);
server = new TcpServer(this);
connect(server,SIGNAL(sendFileName(QString)),this,SLOT(sentFileName(QString)));
connect(ui-&textEdit,SIGNAL(currentCharFormatChanged(QTextCharFormat)),this,SLOT(currentFormatChanged(const QTextCharFormat)));
void Widget::currentFormatChanged(const QTextCharFormat &format)
{//当编辑器的字体格式改变时,我们让部件状态也随之改变
ui-&fontComboBox-&setCurrentFont(format.font());
if(format.fontPointSize()&9)
//如果字体大小出错,因为我们最小的字体为9
ui-&fontsizecomboBox-&setCurrentIndex(3); //即显示12
ui-&fontsizecomboBox-&setCurrentIndex(ui-&fontsizecomboBox-&findText(QString::number(format.fontPointSize())));
ui-&textbold-&setChecked(format.font().bold());
ui-&textitalic-&setChecked(format.font().italic());
ui-&textUnderline-&setChecked(format.font().underline());
color = format.foreground().color();
void Widget::processPendingDatagrams()
//接收数据UDP
while(udpSocket-&hasPendingDatagrams())
datagram.resize(udpSocket-&pendingDatagramSize());
udpSocket-&readDatagram(datagram.data(),datagram.size());
QDataStream in(&datagram,QIODevice::ReadOnly);
int messageT
in && messageT
QString userName,localHostName,ipAddress,
QString time = QDateTime::currentDateTime().toString(&yyyy-MM-dd hh:mm:ss&);
switch(messageType)
case Message:
in &&userName &&localHostName &&ipAddress &&
ui-&textBrowser-&setTextColor(Qt::blue);
ui-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,12));
ui-&textBrowser-&append(&[ & +localHostName+& ] &+ time);
ui-&textBrowser-&append(message);
case NewParticipant:
in &&userName &&localHostName &&ipA
newParticipant(userName,localHostName,ipAddress);
case ParticipantLeft:
in &&userName &&localHostN
participantLeft(userName,localHostName,time);
case FileName:
in &&userName &&localHostName && ipA
QString clientAddress,fileN
in && clientAddress && fileN
hasPendingFile(userName,ipAddress,clientAddress,fileName);
case Refuse:
in && userName && localHostN
QString serverA
in && serverA
QString ipAddress = getIP();
if(ipAddress == serverAddress)
server-&refused();
case Xchat:
in &&userName &&localHostName &&ipA
showxchat(localHostName,ipAddress);//显示与主机名聊天中,不是用户名
//处理新用户加入
void Widget::newParticipant(QString userName,QString localHostName,QString ipAddress)
bool bb = ui-&tableWidget-&findItems(localHostName,Qt::MatchExactly).isEmpty();
QTableWidgetItem *user = new QTableWidgetItem(userName);
QTableWidgetItem *host = new QTableWidgetItem(localHostName);
QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
ui-&tableWidget-&insertRow(0);
ui-&tableWidget-&setItem(0,0,user);
ui-&tableWidget-&setItem(0,1,host);
ui-&tableWidget-&setItem(0,2,ip);
ui-&textBrowser-&setTextColor(Qt::gray);
ui-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,10));
ui-&textBrowser-&append(tr(&%1 在线!&).arg(localHostName));
ui-&onlineUser-&setText(tr(&在线人数:%1&).arg(ui-&tableWidget-&rowCount()));
sendMessage(NewParticipant);
//处理用户离开
void Widget::participantLeft(QString userName,QString localHostName,QString time)
int rowNum = ui-&tableWidget-&findItems(localHostName,Qt::MatchExactly).first()-&row();
ui-&tableWidget-&removeRow(rowNum);
ui-&textBrowser-&setTextColor(Qt::gray);
ui-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,10));
ui-&textBrowser-&append(tr(&%1 于 %2 离开!&).arg(localHostName).arg(time));
ui-&onlineUser-&setText(tr(&在线人数:%1&).arg(ui-&tableWidget-&rowCount()));
Widget::~Widget()
privatechat = NULL;
//udpSocket
void Widget::changeEvent(QEvent *e)
QWidget::changeEvent(e);
switch (e-&type()) {
case QEvent::LanguageChange:
ui-&retranslateUi(this);
QString Widget::getIP()
//获取ip地址
QList&QHostAddress& list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
if(address.protocol() == QAbstractSocket::IPv4Protocol) //我们使用IPv4地址
return address.toString();
void Widget::sendMessage(MessageType type, QString serverAddress)
//发送信息
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out && type && getUserName() && localHostN
switch(type)
case ParticipantLeft:
case NewParticipant:
case Message :
if(ui-&textEdit-&toPlainText() == &&)
QMessageBox::warning(0,tr(&警告&),tr(&发送内容不能为空&),QMessageBox::Ok);
out && address && getMessage();
ui-&textBrowser-&verticalScrollBar()-&setValue(ui-&textBrowser-&verticalScrollBar()-&maximum());
case FileName:
int row = ui-&tableWidget-&currentRow();
QString clientAddress = ui-&tableWidget-&item(row,2)-&text();
out && address && clientAddress && fileN
case Refuse:
out && serverA
udpSocket-&writeDatagram(data,data.length(),QHostAddress::Broadcast, port);
QString Widget::getUserName()
//获取用户名
QStringList envV
envVariables && &USERNAME.*& && &USER.*& && &USERDOMAIN.*&
&& &HOSTNAME.*& && &DOMAINNAME.*&;
QStringList environment = QProcess::systemEnvironment();
foreach (QString string, envVariables)
int index = environment.indexOf(QRegExp(string));
if (index != -1)
QStringList stringList = environment.at(index).split('=');
if (stringList.size() == 2)
return stringList.at(1);
QString Widget::getMessage()
//获得要发送的信息
QString msg = ui-&textEdit-&toHtml();
ui-&textEdit-&clear();
ui-&textEdit-&setFocus();
void Widget::closeEvent(QCloseEvent *)
sendMessage(ParticipantLeft);
void Widget::sentFileName(QString fileName)
this-&fileName = fileN
sendMessage(FileName);
void Widget::hasPendingFile(QString userName,QString serverAddress,
//接收文件
QString clientAddress,QString fileName)
QString ipAddress = getIP();
if(ipAddress == clientAddress)
int btn = QMessageBox::information(this,tr(&接受文件&),
tr(&来自%1(%2)的文件:%3,是否接收?&)
.arg(userName).arg(serverAddress).arg(fileName),
QMessageBox::Yes,QMessageBox::No);
if(btn == QMessageBox::Yes)
QString name = QFileDialog::getSaveFileName(0,tr(&保存文件&),fileName);
if(!name.isEmpty())
TcpClient *client = new TcpClient(this);
client-&setFileName(name);
client-&setHostAddress(QHostAddress(serverAddress));
client-&show();
sendMessage(Refuse,serverAddress);
void Widget::on_send_clicked()//发送
sendMessage(Message);
void Widget::on_sendfile_clicked()
if(ui-&tableWidget-&selectedItems().isEmpty())
QMessageBox::warning(0,tr(&选择用户&),tr(&请先从用户列表选择要传送的用户!&),QMessageBox::Ok);
server-&show();
server-&initServer();
void Widget::on_close_clicked()//关闭
this-&close();
bool Widget::eventFilter(QObject *target, QEvent *event)
if(target == ui-&textEdit)
if(event-&type() == QEvent::KeyPress)//回车键
QKeyEvent *k = static_cast&QKeyEvent *&(event);
if(k-&key() == Qt::Key_Return)
on_send_clicked();
return QWidget::eventFilter(target,event);
void Widget::on_fontComboBox_currentFontChanged(QFont f)//字体设置
ui-&textEdit-&setCurrentFont(f);
ui-&textEdit-&setFocus();
//字体大小设置
void Widget::on_fontsizecomboBox_currentIndexChanged(QString size)
ui-&textEdit-&setFontPointSize(size.toDouble());
ui-&textEdit-&setFocus();
void Widget::on_textbold_clicked(bool checked)
if(checked)
ui-&textEdit-&setFontWeight(QFont::Bold);
ui-&textEdit-&setFontWeight(QFont::Normal);
ui-&textEdit-&setFocus();
void Widget::on_textitalic_clicked(bool checked)
ui-&textEdit-&setFontItalic(checked);
ui-&textEdit-&setFocus();
void Widget::on_textUnderline_clicked(bool checked)
ui-&textEdit-&setFontUnderline(checked);
ui-&textEdit-&setFocus();
void Widget::on_textcolor_clicked()
color = QColorDialog::getColor(color,this);
if(color.isValid())
ui-&textEdit-&setTextColor(color);
ui-&textEdit-&setFocus();
void Widget::on_save_clicked()//保存聊天记录
if(ui-&textBrowser-&document()-&isEmpty())
QMessageBox::warning(0,tr(&警告&),tr(&聊天记录为空,无法保存!&),QMessageBox::Ok);
//获得文件名,注意getSaveFileName函数的格式即可
QString fileName = QFileDialog::getSaveFileName(this,tr(&保存聊天记录&),tr(&聊天记录&),tr(&文本(*.txt);;All File(*.*)&));
if(!fileName.isEmpty())
saveFile(fileName);
bool Widget::saveFile(const QString &fileName)//保存文件
QFile file(fileName);
if(!file.open(QFile::WriteOnly | QFile::Text))
QMessageBox::warning(this,tr(&保存文件&),
tr(&无法保存文件 %1:\n %2&).arg(fileName)
.arg(file.errorString()));
QTextStream out(&file);
out && ui-&textBrowser-&toPlainText();
void Widget::on_clear_clicked()//清空聊天记录
ui-&textBrowser-&clear();
void Widget::on_tableWidget_doubleClicked(QModelIndex index)
if(ui-&tableWidget-&item(index.row(),0)-&text() == getUserName() &&
ui-&tableWidget-&item(index.row(),2)-&text() == getIP())
QMessageBox::warning(0,tr(&警告&),tr(&你不可以跟自己聊天!!!&),QMessageBox::Ok);
if(!privatechat){
chat *privatechatT
privatechat = new chat(ui-&tableWidget-&item(index.row(),1)-&text(), //接收主机名
ui-&tableWidget-&item(index.row(),2)-&text()) ;//接收用户IP
if( privatechat-&is_opened )//如果其曾经显示过则删除掉
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out && Xchat && getUserName() && localHostName &&
udpSocket-&writeDatagram(data,data.length(),QHostAddress::QHostAddress(ui-&tableWidget-&item(index.row(),2)-&text()), port);
privatechat-&xchat-&writeDatagram(data,data.length(),QHostAddress::QHostAddress(ui-&tableWidget-&item(index.row(),2)-&text()), 45456);
if(!privatechat-&is_opened)
privatechat-&show();
privatechat-&is_opened =
(privatechat-&a) = 0;
void Widget::showxchat(QString name, QString ip)
if(!privatechat){
// chat *privatechatT
if(!privatechat1)
privatechat1 = new chat(name,ip);
privatechat = privatechatT}
chat privatechat(name,ip);//如果不用new函数,则程序运行时只是闪烁显示一下就没了,因为类的生命周期结束了
privatechat-&is_opened =
// privatechat-&show();
//privatechat.textBrowser.show();
//privatechat-&is_opened =
tcpclient.h:
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include &QDialog&
#include &QTcpSocket&
#include &QHostAddress&
#include &QFile&
#include &QTime&
namespace Ui {
class TcpC
class TcpClient : public QDialog
explicit TcpClient(QWidget *parent = 0);
~TcpClient();
void setHostAddress(QHostAddress address);
void setFileName(QString fileName){localFile = new QFile(fileName);}
protected:
void changeEvent(QEvent *e);
Ui::TcpClient *
QTcpSocket *tcpC
quint16 blockS
QHostAddress hostA
qint16 tcpP
qint64 TotalB
qint64 bytesR
qint64 bytesToR
qint64 fileNameS
QString fileN
QFile *localF
QByteArray inB
private slots:
void on_tcpClientCancleBtn_clicked();
void on_tcpClientCloseBtn_clicked();
void newConnect();
void readMessage();
void displayError(QAbstractSocket::SocketError);
#endif // TCPCLIENT_H
tcpclient.cpp:
#include &tcpserver.h&
#include &ui_tcpserver.h&
#include &QTcpSocket&
#include &QFileDialog&
#include &QMessageBox&
TcpServer::TcpServer(QWidget *parent):QDialog(parent),
ui(new Ui::TcpServer)
ui-&setupUi(this);
this-&setFixedSize(350,180);
tcpPort = 6666;
tcpServer = new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendMessage()));
initServer();
TcpServer::~TcpServer()
void TcpServer::changeEvent(QEvent *e)
QDialog::changeEvent(e);
switch (e-&type()) {
case QEvent::LanguageChange:
ui-&retranslateUi(this);
void TcpServer::sendMessage()
//开始发送数据
ui-&serverSendBtn-&setEnabled(false);
clientConnection = tcpServer-&nextPendingConnection();
connect(clientConnection,SIGNAL(bytesWritten(qint64)),SLOT(updateClientProgress(qint64)));
ui-&serverStatusLabel-&setText(tr(&开始传送文件 %1 !&).arg(theFileName));
localFile = new QFile(fileName);
if(!localFile-&open((QFile::ReadOnly))){//以只读方式打开
QMessageBox::warning(this,tr(&应用程序&),tr(&无法读取文件 %1:\n%2&).arg(fileName).arg(localFile-&errorString()));
TotalBytes = localFile-&size();
QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_4_6);
time.start();
//开始计时
QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
sendOut&&qint64(0)&&qint64(0)&&currentF
TotalBytes += outBlock.size();
sendOut.device()-&seek(0);
sendOut&&TotalBytes&&qint64((outBlock.size()-sizeof(qint64)*2));
bytesToWrite = TotalBytes - clientConnection-&write(outBlock);
qDebug()&&currentFile&&TotalB
outBlock.resize(0);
void TcpServer::updateClientProgress(qint64 numBytes)//更新进度条
bytesWritten += (int)numB
if(bytesToWrite & 0){
outBlock = localFile-&read(qMin(bytesToWrite,loadSize));
bytesToWrite -= (int)clientConnection-&write(outBlock);
outBlock.resize(0);
localFile-&close();
ui-&progressBar-&setMaximum(TotalBytes);
ui-&progressBar-&setValue(bytesWritten);
float useTime = time.elapsed();
double speed = bytesWritten / useT
ui-&serverStatusLabel-&setText(tr(&已发送 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒&)
.arg(bytesWritten / ())//已发送
.arg(speed**1024),0,'f',2)//速度
.arg(TotalBytes / (1024 * 1024))//总大小
.arg(useTime/1000,0,'f',0)//用时
.arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));//剩余时间
//num.sprintf(&%.1f KB/s&, (bytesWritten*1000) / (1024.0*time.elapsed()));
if(bytesWritten == TotalBytes)
ui-&serverStatusLabel-&setText(tr(&传送文件 %1 成功&).arg(theFileName));
void TcpServer::on_serverOpenBtn_clicked()
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
theFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
ui-&serverStatusLabel-&setText(tr(&要传送的文件为:%1 &).arg(theFileName));
ui-&serverSendBtn-&setEnabled(true);
ui-&serverOpenBtn-&setEnabled(false);
void TcpServer::refused()
//被对方拒绝
tcpServer-&close();
ui-&serverStatusLabel-&setText(tr(&对方拒绝接收!!!&));
void TcpServer::on_serverSendBtn_clicked()
if(!tcpServer-&listen(QHostAddress::Any,tcpPort))//开始监听
qDebug() && tcpServer-&errorString();
ui-&serverStatusLabel-&setText(tr(&等待对方接收... ...&));
emit sendFileName(theFileName);
void TcpServer::on_serverCloseBtn_clicked()//退出
if(tcpServer-&isListening())
tcpServer-&close();
clientConnection-&abort();
this-&close();
void TcpServer::initServer()//初始化
loadSize = 4*1024;
TotalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
ui-&serverStatusLabel-&setText(tr(&请选择要传送的文件&));
ui-&progressBar-&reset();
ui-&serverOpenBtn-&setEnabled(true);
ui-&serverSendBtn-&setEnabled(false);
tcpServer-&close();
tcpserver.h:
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include &QDialog&
#include &QTcpServer&
#include &QFile&
#include &QTime&
namespace Ui {
class TcpS
class TcpServer : public QDialog
explicit TcpServer(QWidget *parent = 0);
~TcpServer();
void refused();
void initServer();
protected:
void changeEvent(QEvent *e);
Ui::TcpServer *
qint16 tcpP
QTcpServer *tcpS
QString fileN
QString theFileN
QFile *localF
qint64 TotalB
qint64 bytesW
qint64 bytesToW
qint64 loadS
QByteArray outB//缓存一次发送的数据
QTcpSocket *clientC
QT//计时器
private slots:
void on_serverSendBtn_clicked();
void on_serverCloseBtn_clicked();
void on_serverOpenBtn_clicked();
void sendMessage();
void updateClientProgress(qint64 numBytes);
void sendFileName(QString fileName);
#endif // TCPSERVER_H
tcpserver.cpp:
#include &tcpserver.h&
#include &ui_tcpserver.h&
#include &QTcpSocket&
#include &QFileDialog&
#include &QMessageBox&
TcpServer::TcpServer(QWidget *parent):QDialog(parent),
ui(new Ui::TcpServer)
ui-&setupUi(this);
this-&setFixedSize(350,180);
tcpPort = 6666;
tcpServer = new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendMessage()));
initServer();
TcpServer::~TcpServer()
void TcpServer::changeEvent(QEvent *e)
QDialog::changeEvent(e);
switch (e-&type()) {
case QEvent::LanguageChange:
ui-&retranslateUi(this);
void TcpServer::sendMessage()
//开始发送数据
ui-&serverSendBtn-&setEnabled(false);
clientConnection = tcpServer-&nextPendingConnection();
connect(clientConnection,SIGNAL(bytesWritten(qint64)),SLOT(updateClientProgress(qint64)));
ui-&serverStatusLabel-&setText(tr(&开始传送文件 %1 !&).arg(theFileName));
localFile = new QFile(fileName);
if(!localFile-&open((QFile::ReadOnly))){//以只读方式打开
QMessageBox::warning(this,tr(&应用程序&),tr(&无法读取文件 %1:\n%2&).arg(fileName).arg(localFile-&errorString()));
TotalBytes = localFile-&size();
QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_4_6);
time.start();
//开始计时
QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
sendOut&&qint64(0)&&qint64(0)&&currentF
TotalBytes += outBlock.size();
sendOut.device()-&seek(0);
sendOut&&TotalBytes&&qint64((outBlock.size()-sizeof(qint64)*2));
bytesToWrite = TotalBytes - clientConnection-&write(outBlock);
qDebug()&&currentFile&&TotalB
outBlock.resize(0);
void TcpServer::updateClientProgress(qint64 numBytes)//更新进度条
bytesWritten += (int)numB
if(bytesToWrite & 0){
outBlock = localFile-&read(qMin(bytesToWrite,loadSize));
bytesToWrite -= (int)clientConnection-&write(outBlock);
outBlock.resize(0);
localFile-&close();
ui-&progressBar-&setMaximum(TotalBytes);
ui-&progressBar-&setValue(bytesWritten);
float useTime = time.elapsed();
double speed = bytesWritten / useT
ui-&serverStatusLabel-&setText(tr(&已发送 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒&)
.arg(bytesWritten / ())//已发送
.arg(speed**1024),0,'f',2)//速度
.arg(TotalBytes / (1024 * 1024))//总大小
.arg(useTime/1000,0,'f',0)//用时
.arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));//剩余时间
//num.sprintf(&%.1f KB/s&, (bytesWritten*1000) / (1024.0*time.elapsed()));
if(bytesWritten == TotalBytes)
ui-&serverStatusLabel-&setText(tr(&传送文件 %1 成功&).arg(theFileName));
void TcpServer::on_serverOpenBtn_clicked()
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
theFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);
ui-&serverStatusLabel-&setText(tr(&要传送的文件为:%1 &).arg(theFileName));
ui-&serverSendBtn-&setEnabled(true);
ui-&serverOpenBtn-&setEnabled(false);
void TcpServer::refused()
//被对方拒绝
tcpServer-&close();
ui-&serverStatusLabel-&setText(tr(&对方拒绝接收!!!&));
void TcpServer::on_serverSendBtn_clicked()
if(!tcpServer-&listen(QHostAddress::Any,tcpPort))//开始监听
qDebug() && tcpServer-&errorString();
ui-&serverStatusLabel-&setText(tr(&等待对方接收... ...&));
emit sendFileName(theFileName);
void TcpServer::on_serverCloseBtn_clicked()//退出
if(tcpServer-&isListening())
tcpServer-&close();
clientConnection-&abort();
this-&close();
void TcpServer::initServer()//初始化
loadSize = 4*1024;
TotalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
ui-&serverStatusLabel-&setText(tr(&请选择要传送的文件&));
ui-&progressBar-&reset();
ui-&serverOpenBtn-&setEnabled(true);
ui-&serverSendBtn-&setEnabled(false);
tcpServer-&close();
#ifndef CHAT_H
#define CHAT_H
#include &QDialog&
#include &QtNetwork&
#include &QtGui&
#include &tcpclient.h&
#include &tcpserver.h&
namespace Ui {
enum MessageType
NewParticipant,
ParticipantLeft,
class chat : public QDialog
chat(QString pasvusername, QString pasvuserip);
QUdpSocket *
void sendMessage(MessageType type,QString serverAddress=&&);
qint32 is_opened = 0;
public slots:
protected:
void hasPendingFile(QString userName,QString serverAddress,
//接收文件
QString clientAddress,QString fileName);
void participantLeft(QString userName,QString localHostName,QString time);
bool eventFilter(QObject *target, QEvent *event); //事件过滤器
Ui::chat *
TcpServer *
bool saveFile(const QString& fileName);//保存聊天记录
QString getMessage();
QString getIP();
QString getUserName();
QString fileN
private slots:
void sentFileName(QString);
void on_sendfile_clicked();
void processPendingDatagrams();
void on_send_clicked();
void on_close_clicked();
void on_clear_clicked();
void on_save_clicked();
void on_textcolor_clicked();
void on_textUnderline_clicked(bool checked);
void on_textitalic_clicked(bool checked);
void on_textbold_clicked(bool checked);
void on_fontComboBox_currentFontChanged(QFont f);
void on_fontsizecomboBox_currentIndexChanged(QString );
void currentFormatChanged(const QTextCharFormat &format);
#endif // CHAT_H
#include &chat.h&
#include &ui_chat.h&
//chat::chat():ui(new Ui::chat)
is_opened =
chat::chat(QString pasvusername, QString pasvuserip) : ui(new Ui::chat)
ui-&setupUi(this);
ui-&textEdit-&setFocusPolicy(Qt::StrongFocus);
ui-&textBrowser-&setFocusPolicy(Qt::NoFocus);
ui-&textEdit-&setFocus();
ui-&textEdit-&installEventFilter(this);
is_opened =
this-&is_opened =
xpasvusername =
xpasvuserip =
ui-&label-&setText(tr(&与%1聊天中
对方IP:%2&).arg(xpasvusername).arg(pasvuserip));
xchat = new QUdpSocket(this);
xport = 45456;
xchat-&bind(xport, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
xchat-&bind( QHostAddress::QHostAddress(getIP()), xport );
connect(xchat, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
server = new TcpServer(this);
connect(server,SIGNAL(sendFileName(QString)),this,SLOT(sentFileName(QString)));
connect(ui-&textEdit,SIGNAL(currentCharFormatChanged(QTextCharFormat)),this,SLOT(currentFormatChanged(const QTextCharFormat)));
chat::~chat()
is_opened =
bool chat::eventFilter(QObject *target, QEvent *event)
if(target == ui-&textEdit)
if(event-&type() == QEvent::KeyPress)//按下键盘某键
QKeyEvent *k = static_cast&QKeyEvent *&(event);
if(k-&key() == Qt::Key_Return)//回车键
on_send_clicked();
return QWidget::eventFilter(target,event);
//处理用户离开
void chat::participantLeft(QString userName,QString localHostName,QString time)
ui-&textBrowser-&setTextColor(Qt::gray);
ui-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,10));
ui-&textBrowser-&append(tr(&%1 于 %2 离开!&).arg(userName).arg(time));
QString chat::getUserName()
//获取用户名
QStringList envV
envVariables && &USERNAME.*& && &USER.*& && &USERDOMAIN.*&
&& &HOSTNAME.*& && &DOMAINNAME.*&;
QStringList environment = QProcess::systemEnvironment();
foreach (QString string, envVariables)
int index = environment.indexOf(QRegExp(string));
if (index != -1)
QStringList stringList = environment.at(index).split('=');
if (stringList.size() == 2)
return stringList.at(1);
QString chat::getIP()
//获取ip地址
QList&QHostAddress& list = QNetworkInterface::allAddresses();
foreach (QHostAddress address, list)
if(address.protocol() == QAbstractSocket::IPv4Protocol) //我们使用IPv4地址
return address.toString();
void chat::hasPendingFile(QString userName,QString serverAddress,
//接收文件
QString clientAddress,QString fileName)
QString ipAddress = getIP();
if(ipAddress == clientAddress)
int btn = QMessageBox::information(this,tr(&接受文件&),
tr(&来自%1(%2)的文件:%3,是否接收?&)
.arg(userName).arg(serverAddress).arg(fileName),
QMessageBox::Yes,QMessageBox::No);
if(btn == QMessageBox::Yes)
QString name = QFileDialog::getSaveFileName(0,tr(&保存文件&),fileName);
if(!name.isEmpty())
TcpClient *client = new TcpClient(this);
client-&setFileName(name);
client-&setHostAddress(QHostAddress(serverAddress));
client-&show();
sendMessage(Refuse,serverAddress);
void chat::processPendingDatagrams()
//接收数据UDP
while(xchat-&hasPendingDatagrams())
datagram.resize(xchat-&pendingDatagramSize());
xchat-&readDatagram(datagram.data(),datagram.size());
QDataStream in(&datagram,QIODevice::ReadOnly);
int messageT
in && messageT
QString userName,localHostName,ipAddress,
QString time = QDateTime::currentDateTime().toString(&yyyy-MM-dd hh:mm:ss&);
switch(messageType)
case Xchat:
ui.show();
case Message:
//这2条语句都没有用。why??、
/*this-&hide();
this-&close();*/
in &&userName &&localHostName &&ipAddress &&
ui-&textBrowser-&setTextColor(Qt::blue);
ui-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,12));
ui-&textBrowser-&append(&[ & +localHostName+& ] &+ time);//与主机名聊天中
ui-&textBrowser-&append(messagestr);
ui-&textBrowser-&show();
//this-&textBrowser-&setTextColor(Qt::blue);
//this-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,12));
//this-&textBrowser-&append(&[ & +localHostName+& ] &+ time);//与主机名聊天中
//this-&textBrowser-&append(messagestr);
if( is_opened == false )//加了这句,接收端B不显示端口了
this-&show();////解决bug1.收到私聊消息后才显示
ui-&textBrowser-&show();
this-&show();
ui-&textBrowser-&show();
ui.show();
if( this-&show() )
this-&hide();
is_opened =
case FileName:
in &&userName &&localHostName && ipA
QString clientAddress,fileN
in && clientAddress && fileN
hasPendingFile(userName,ipAddress,clientAddress,fileName);
case Refuse:
in && userName && localHostN
QString serverA
in && serverA
QString ipAddress = getIP();
if(ipAddress == serverAddress)
server-&refused();
case ParticipantLeft:
in &&userName &&localHostN
participantLeft(userName,localHostName,time);
QMessageBox::information(0,tr(&本次对话关闭&),tr(&对方结束了对话&),QMessageBox::Ok);
ui-&textBrowser-&clear();
//is_opened =
this-&is_opened =
ui-&~chat();
void chat::sentFileName(QString fileName)
this-&fileName = fileN
sendMessage(FileName);
QString chat::getMessage()
//获得要发送的信息
QString msg = ui-&textEdit-&toHtml();
qDebug()&&
ui-&textEdit-&clear();
ui-&textEdit-&setFocus();
//通过私聊套接字发送到对方的私聊专用端口上
void chat::sendMessage(MessageType type , QString serverAddress)
//发送信息
QDataStream out(&data,QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIP();
out && type && getUserName() && localHostN
switch(type)
case ParticipantLeft:
case Message :
if(ui-&textEdit-&toPlainText() == &&)
QMessageBox::warning(0,tr(&警告&),tr(&发送内容不能为空&),QMessageBox::Ok);
message = getMessage();
out && address &&
ui-&textBrowser-&verticalScrollBar()-&setValue(ui-&textBrowser-&verticalScrollBar()-&maximum());
case FileName:
QString clientAddress =
out && address && clientAddress && fileN
case Refuse:
out && serverA
xchat-&writeDatagram(data,data.length(),QHostAddress::QHostAddress(xpasvuserip), 45456);
void chat::currentFormatChanged(const QTextCharFormat &format)
{//当编辑器的字体格式改变时,我们让部件状态也随之改变
ui-&fontComboBox-&setCurrentFont(format.font());
if(format.fontPointSize()&9)
//如果字体大小出错,因为我们最小的字体为9
ui-&fontsizecomboBox-&setCurrentIndex(3); //即显示12
ui-&fontsizecomboBox-&setCurrentIndex(ui-&fontsizecomboBox-&findText(QString::number(format.fontPointSize())));
ui-&textbold-&setChecked(format.font().bold());
ui-&textitalic-&setChecked(format.font().italic());
ui-&textUnderline-&setChecked(format.font().underline());
color = format.foreground().color();
void chat::on_fontComboBox_currentFontChanged(QFont f)//字体设置
ui-&textEdit-&setCurrentFont(f);
ui-&textEdit-&setFocus();
void chat::on_fontsizecomboBox_currentIndexChanged(QString size)
ui-&textEdit-&setFontPointSize(size.toDouble());
ui-&textEdit-&setFocus();
void chat::on_textbold_clicked(bool checked)
if(checked)
ui-&textEdit-&setFontWeight(QFont::Bold);
ui-&textEdit-&setFontWeight(QFont::Normal);
ui-&textEdit-&setFocus();
void chat::on_textitalic_clicked(bool checked)
ui-&textEdit-&setFontItalic(checked);
ui-&textEdit-&setFocus();
void chat::on_save_clicked()//保存聊天记录
if(ui-&textBrowser-&document()-&isEmpty())
QMessageBox::warning(0,tr(&警告&),tr(&聊天记录为空,无法保存!&),QMessageBox::Ok);
//获得文件名
QString fileName = QFileDialog::getSaveFileName(this,tr(&保存聊天记录&),tr(&聊天记录&),tr(&文本(*.txt);;All File(*.*)&));
if(!fileName.isEmpty())
saveFile(fileName);
void chat::on_clear_clicked()//清空聊天记录
ui-&textBrowser-&clear();
bool chat::saveFile(const QString &fileName)//保存文件
QFile file(fileName);
if(!file.open(QFile::WriteOnly | QFile::Text))
QMessageBox::warning(this,tr(&保存文件&),
tr(&无法保存文件 %1:\n %2&).arg(fileName)
.arg(file.errorString()));
QTextStream out(&file);
out && ui-&textBrowser-&toPlainText();
void chat::on_textUnderline_clicked(bool checked)
ui-&textEdit-&setFontUnderline(checked);
ui-&textEdit-&setFocus();
void chat::on_textcolor_clicked()
color = QColorDialog::getColor(color,this);
if(color.isValid())
ui-&textEdit-&setTextColor(color);
ui-&textEdit-&setFocus();
void chat::on_close_clicked()
sendMessage(ParticipantLeft);
ui-&textBrowser-&clear();
//is_opened =
this-&is_opened =
ui-&~chat();
//this-&close();
void chat::on_send_clicked()
sendMessage(Message);
QString localHostName = QHostInfo::localHostName();
QString time = QDateTime::currentDateTime().toString(&yyyy-MM-dd hh:mm:ss&);
ui-&textBrowser-&setTextColor(Qt::blue);
ui-&textBrowser-&setCurrentFont(QFont(&Times New Roman&,12));
ui-&textBrowser-&append(&[ & +localHostName+& ] &+ time);
ui-&textBrowser-&append(message);
is_opened =
void chat::on_sendfile_clicked()
server-&show();
server-&initServer();
#include &QtGui/QApplication&
#include &widget.h&
int main(int argc, char *argv[])
QApplication a(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
return a.exec();
作者:tornadomeet 出处:/tornadomeet 欢迎转载或分享,但请务必声明文章出处。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:47283次
排名:千里之外
原创:36篇
转载:48篇
(2)(1)(3)(5)(4)(4)(26)(12)(14)(7)(6)

我要回帖

更多关于 qt 加载dll 的文章

 

随机推荐