QML与C++混合编程详解(转)
原文转自:http://blog.csdn.net/ieearth/article/details/42243553
原文转自:https://www.cnblogs.com/findumars/p/6090850.html
1、QML与C++为什么要混合编程
QML与C++为什么要混合编程,简单来说,就是使用QML高效便捷地构建UI,而C++则用来实现业务逻辑和复杂算法,下面介绍了两者间交互的方法与技巧。
2、QML访问C++概述
Qt集成了QML引擎和Qt元对象系统,使得QML很容易从C++中得到扩展,在一定的条件下,QML就可以访问QObject派生类的成员,例如信号、槽函数、枚举类型、属性、成员函数等。
QML访问C++有两个方法:一是在Qt元对象系统中注册C++类,在QML中实例化、访问。二是在C++中实例化并设置为QML上下文属性,在QML中直接使用。与后者相比,前者可以使C++类在QML中作为一个数据类型,例如函数参数类型或属性类型,也可以使用其枚举类型、单例等,功能更强大。
3、如何实现可以被QML访问的C++类
C++类要想被QML访问,首先必须满足两个条件:一是派生自QObject类或QObject类的子类,二是使用Q_OBJECT宏。QObject类是所有Qt对象的基类,作为Qt对象模型的核心,提供了信号与槽机制等很多重要特性。Q_OBJECT宏必须在private区(C++默认为private)声明,用来声明信号与槽,使用Qt元对象系统提供的内容,位置一般在语句块首行。下面例子在QtCreator3.1.2中创建,Projects选择QtQuickApplication,工程名为Gemini,Component选择QtQuick2.2,然后在自动生成的文件中添砖加瓦。
信号与槽——
(1)添加头文件Gemini.h
#ifndef GEMINI_H
#define GEMINI_H
// Gemini.h
#include <QObject>
#include <QDebug>
class Gemini : public QObject
{
Q_OBJECT
signals :
void begin();
public slots:
void doSomething() {
qDebug() << "Gemini::doSomething() called";
}
};
#endif // GEMINI_H
Gemini类中的信号begin()和槽doSomething()都可以被QML访问。槽必须声明为public或protected,信号在C++中使用时要用到emit关键字,但在QML中就是个普通的函数,用法同函数一样,信号处理器形式为on<Signal>,Signal首字母大写。信号不支持重载,多个信号的名字相同而参数不同时,能够被识别的只是最后一个信号,与信号的参数无关。
(2)修改main.cpp
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <Gemini.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Gemini>("Union.Lotto.Gemini", , , "Gemini");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
这里把Gemini类注册(qmlRegisterType)到了Qt元对象系统,当然也可以先实例化再设置为QML上下文属性,相关内容将在后面详细介绍。
(3)修改main.qml
// main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window{
visible: true
width : ; height:
title : "Union Lotto Game"
color : "white"
MouseArea{
anchors.fill: parent
onClicked : {
gemini.begin()
}
}
Gemini{
id: gemini
onBegin : doSomething()
}
}
Gemini类注册到Qt元对象系统后,并且在QML文件中导入(import),关键字Gemini就可以在当前QML文件中当作一种QML类型来用了。例子中有个MouseArea,单击鼠标时会发送begin()信号,进而调用doSomething()槽函数。
枚举类型——
(1)修改头文件Gemini.h
#ifndef GEMINI_H
#define GEMINI_H
// Gemini.h
#include <QObject>
#include <QDebug>
class Gemini : public QObject
{
Q_OBJECT
Q_ENUMS(BALL_COLOR)
public:
Gemini() : m_ballColor(BALL_COLOR_YELLOW) {
qDebug() << "Gemini::Gemini() called";
}
enum BALL_COLOR {
BALL_COLOR_YELLOW,
BALL_COLOR_RED,
BALL_COLOR_BLUE,
BALL_COLOR_ALL
};
signals:
void begin();
public slots:
void doSomething(BALL_COLOR ballColor) {
qDebug() << "Gemini::doSomething() called with" << ballColor;
if (ballColor != m_ballColor) {
m_ballColor = ballColor;
qDebug() << "ball color changed";
}
}
private:
BALL_COLOR m_ballColor;
};
#endif // GEMINI_H
Gemini类中添加了public的BALL_COLOR枚举类型,这个枚举类型要想在QML中使用,就用到了Q_ENUMS()宏。
(2)修改main.qml
// main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window{
visible: true
width : ; height:
title : "Union Lotto Game"
color : "white"
MouseArea{
anchors.fill: parent
onClicked : {
gemini.begin()
}
}
Gemini{
id: gemini
onBegin : doSomething(Gemini.BALL_COLOR_RED)
}
}
在QML中使用枚举类型的方式是<CLASS_NAME>.<ENUM_VALUE>,例如Gemini.BALL_COLOR_RED。
成员函数——
(1)修改头文件Gemini.h
#ifndef GEMINI_H
#define GEMINI_H
// Gemini.h
#include <QObject>
#include <QDebug>
class Gemini : public QObject
{
Q_OBJECT
Q_ENUMS(BALL_COLOR)
public:
Gemini() : m_ballColor(BALL_COLOR_YELLOW) {
qDebug() << "Gemini::Gemini() called";
}
enum BALL_COLOR {
BALL_COLOR_YELLOW,
BALL_COLOR_RED,
BALL_COLOR_BLUE,
BALL_COLOR_ALL
};
Q_INVOKABLE void stop() {
qDebug() << "Gemini::stop() called";
}
signals:
void begin();
public slots:
void doSomething(BALL_COLOR ballColor) {
qDebug() << "Gemini::doSomething() called with" << ballColor;
if (ballColor != m_ballColor) {
m_ballColor = ballColor;
qDebug() << "ball color changed";
}
}
private:
BALL_COLOR m_ballColor;
};
#endif // GEMINI_H
Gemini类中添加了成员函数stop(),在QML中访问的前提是public或protected成员函数,且使用Q_INVOKABLE宏,位置在函数返回类型的前面。
(2)修改main.qml
// main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window {
visible: true
width: ; height:
title: "Union Lotto Game"
color: "white"
MouseArea {
anchors.fill: parent
onClicked: {
gemini.begin()
gemini.stop()
}
}
Gemini {
id: gemini
onBegin: doSomething(Gemini.BALL_COLOR_RED)
}
}
在QML中访问C++的成员函数的形式是<id>.<method>,例如gemini.stop()。支持函数重载,这个与信号不同。
C++类的属性——
(1)修改头文件Gemini.h
#ifndef GEMINI_H
#define GEMINI_H
// Gemini.h
#include <QObject>
#include <QDebug>
class Gemini : public QObject
{
Q_OBJECT
Q_ENUMS(BALL_COLOR)
Q_PROPERTY(unsigned int ballNumber READ ballNumber WRITE setBallNumber NOTIFY ballNumberChanged)
public:
Gemini() : m_ballColor(BALL_COLOR_YELLOW), m_ballNumber() {
qDebug() << "Gemini::Gemini() called";
}
enum BALL_COLOR {
BALL_COLOR_YELLOW,
BALL_COLOR_RED,
BALL_COLOR_BLUE,
BALL_COLOR_ALL
};
unsigned int ballNumber() const {
return m_ballNumber;
}
void setBallNumber(const unsigned int &ballNumber) {
if (ballNumber != m_ballNumber) {
m_ballNumber = ballNumber;
emit ballNumberChanged();
}
}
Q_INVOKABLE void stop() {
qDebug() << "Gemini::stop() called";
}
signals:
void begin();
void ballNumberChanged();
public slots:
void doSomething(BALL_COLOR ballColor) {
qDebug() << "Gemini::doSomething() called with" << ballColor;
if (ballColor != m_ballColor) {
m_ballColor = ballColor;
qDebug() << "ball color changed";
}
}
private:
BALL_COLOR m_ballColor;
unsigned int m_ballNumber;
};
#endif // GEMINI_H
Gemini类中添加了Q_PROPERTY()宏,用来在QObject派生类中声明属性,这个属性如同类的数据成员一样,但它又有一些额外的特性可通过Qt元对象系统来访问。
下面是Q_PROPERTY()宏的原型:
Q_PROPERTY()(type name
(READ getFunction[WRITE setFunction] |
MEMBER memberName[(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
属性的type、name是必需的,其它是可选项,常用的有READ、WRITE、NOTIFY。属性的type可以是QVariant支持的任何类型,也可以是自定义类型,包括自定义类、列表类型、组属性等。另外,属性的READ、WRITE、RESET是可以被继承的,也可以是虚函数,这些特性并不常用。
READ:读取属性值,如果没有设置MEMBER的话,它是必需的。一般情况下,函数是个const函数,返回值类型必须是属性本身的类型或这个类型的const引用,没有参数。
WRITE:设置属性值,可选项。函数必须返回void,有且仅有一个参数,参数类型必须是属性本身的类型或这个类型的指针或引用。
NOTIFY:与属性关联的可选信号。这个信号必须在类中声明过,当属性值改变时,就可触发这个信号,可以没有参数,有参数的话只能是一个类型同属性本身类型的参数,用来记录属性改变后的值。
Q_PROPERTY()的详细用法可参考如下网址:
http://doc.qt.io/qt-5/properties.html#qt-s-property-system
(2)修改main.qml
// main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window {
visible: true
width: ; height:
title: "Union Lotto Game"
color: "white"
MouseArea {
anchors.fill: parent
onClicked: {
gemini.begin()
gemini.stop()
gemini.ballNumber =
}
}
Gemini {
id: gemini
onBegin: doSomething(Gemini.BALL_COLOR_RED)
onBallNumberChanged: console.log("new ball number is", ballNumber) // 10
Component.onCompleted: console.log("default ball number is", ballNumber) // 0
}
}
Gemini类中的ballNumber属性可以在QML中访问、修改,访问时调用了ballNumber()函数,修改时调用了setBallNumber()函数,同时还发送了一个信号来自动更新这个属性值。
4、注册C++类为QML类型
QObject派生类可以注册到Qt元对象系统,使得该类在QML中同其它内建类型一样,可以作为一个数据类型来使用。QML引擎允许注册可实例化的类型,也可以是不可实例化的类型,常见的注册函数有:
qmlRegisterInterface()
qmlRegisterRevision()
qmlRegisterSingletonType()
qmlRegisterType()
qmlRegisterTypeNotAvailable()
qmlRegisterUncreatableType()
这些注册函数各有其用,可根据实际需要选择,使用时需要包含<QtQml>。常用的为qmlRegisterType(),它有三个重载函数,这里只介绍其一:
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
这个模板函数注册C++类到Qt元对象系统中,uri是需要导入到QML中的库名,versionMajor和versionMinor是其版本数字,qmlName是在QML中可以使用的类型名。例如上面例子main.cpp中的代码:
qmlRegisterType<Gemini>("Union.Lotto.Gemini", , , "Gemini");
main.cpp中将Gemini类注册为在QML中可以使用的Gemini类型,主版本为1,次版本为0,库的名字是Union.Lotto.Gemini。main.qml中导入了这个库,使用Gemini构造了一个对象,id为gemini,这样就可以借助id来访问C++了。
注册动作必须在QML上下文创建之前,否则无效。
另外:QQuickView为QtQuickUI提供了一个窗口,可以方便地加载QML文件并显示其界面。QApplication派生自QGuiApplication,而QGuiApplication又派生自QCoreApplication,这三个类是常见的管理Qt应用程序的类。QQmlApplicationEngine可以方便地从一个单一的QML文件中加载应用程序,它派生自QQmlEngine,QQmlEngine则提供了加载QML组件的环境,可以与QQmlComponent、QQmlContext等一起使用。
5、QML上下文属性设置
在C++应用程序加载QML对象时,我们可以直接嵌入一些C++数据来给QML使用,这里需要用到QQmlContext::setContextProperty(),即设置QML上下问属性,它可以是一个简单的类型,也可以是任何我们自定义的类对象。
(1)修改main.cpp
// main.cpp
#include <QGuiApplication>
#include <QQuickView>
#include <QQmlContext>
#include <Gemini.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
Gemini gemini;
view.rootContext()->setContextProperty("gemini", &gemini);
view.setSource(QUrl(QStringLiteral("qrc:///main.qml")));
view.show();
return app.exec();
}
彻底修改一下main.cpp吧,这里使用了QQuickView,注意头文件的变化,Gemini类先实例化为gemini对象,然后注册为QML上下文属性。
(2)修改main.qml
// main.qml
import QtQuick 2.2
Item {
width: ; height:
MouseArea {
anchors.fill: parent
onClicked: {
gemini.begin()
gemini.stop()
}
}
Connections {
target: gemini
onBegin:console.log("aaaa")
}
}
既然main.cpp修改了那么多东西,main.qml也要做相应的修改,在main.qml中不能使用Gemini类型来实例化了,也不能调用doSomething()槽函数了,因为doSomething()函数中的枚举类型在QML中是访问不到的,正确的用法是通过QML上下文属性“gemini”来访问C++,可以访问信号begin()和成员函数stop(),此时的信号处理器就需要用Connections来处理了,如上面例子中所示。
6、C++访问QML
同样,在C++中也可以访问QML中的属性、函数和信号。
在C++中加载QML文件可以用QQmlComponent或QQuickView,然后就可以在C++中访问QML对象了。QQuickView提供了一个显示用户界面的窗口,而QQmlComponent没有。
QQuickView::rootObject()返回了组件实例,是一个有用的函数。前面的例子中已经使用过QQuickView了,下面的例子介绍QQmlComponent的用法。
使用QQmlComponent——
修改main.cpp
// main.cpp
#include <QGuiApplication>
#include <QtQml>
#include <Gemini.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Gemini>("Union.Lotto.Gemini", , , "Gemini");
QQmlEngine engine;
// set qml context property
// Gemini aGemini;
// engine.rootContext()->setContextProperty("aGemini", &aGemini);
QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:///main.qml")));
component.create();
return app.exec();
}
例子中注释的部分是设置QML上下文属性的方法。
在C++中访问QML中的属性——
在C++中加载了QML文件并进行组件实例化后,就可以在C++中访问、修改这个实例的属性值了,可以是QML内建属性,也可以是自定义属性。
(1)修改main.qml
// main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window {
visible: true
width: ; height:
title: "Union Lotto Game"
color: "white"
Rectangle {
objectName: "rect"
anchors.fill: parent
color: "yellow"
}
MouseArea {
anchors.fill: parent
onClicked: {
gemini.begin()
gemini.stop()
gemini.ballNumber =
}
}
Gemini {
id: gemini
onBegin: doSomething(Gemini.BALL_COLOR_RED)
onBallNumberChanged: console.log("new ball number is", ballNumber) // 10
Component.onCompleted: console.log("default ball number is", ballNumber) // 0
}
}
在main.qml中添加了一个Rectangle,设置objectName属性值为“rect”,这个值是为了在C++中能够找到这个Rectangle。
(2)修改main.cpp
// main.cpp
#include <QGuiApplication>
#include <QtQml>
#include <Gemini.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Gemini>("Union.Lotto.Gemini", , , "Gemini");
QQmlEngine engine;
// set qml context property
// Gemini aGemini;
// engine.rootContext()->setContextProperty("aGemini", &aGemini);
QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:///main.qml")));
QObject *object = component.create();
qDebug() << "width value is" << object->property("width").toInt();
object->setProperty("width", );
qDebug() << "height value is" << QQmlProperty::read(object, "height").toInt();
QQmlProperty::write(object, "height", );
QObject *rect = object->findChild<QObject*>("rect");
if(rect) {
rect->setProperty("color", "black");
}
return app.exec();
}
首先,使用了QObject::property()/setProperty()来读取、修改width属性值。
接着,使用了QQmlProperty::read()/write()来读取、修改height属性值。
另外,如果某个对象的类型是QQuickItem,例如QQuickView::rootObject()的返回值,这时就可以使用QQuickItem::width/setWidth()来访问、修改width属性值了。
有时候,QML组件是一个复杂的树型结构,包含兄弟组件和孩子组件,我们可以使用QObject::findchild()/findchildren()来查找,如上面例子所示。
在C++中访问QML中的函数与信号——
在C++中,使用QMetaObject::invokeMethod()可以调用QML中的函数,从QML传递过来的函数参数和返回值会被转换为C++中的QVariant类型,成功返回true,参数不正确或被调用函数名错误返回false,invokeMethod()共有四个重载函数,用法相似。必须使用Q_ARG()宏来声明函数参数,用Q_RETURN_ARG()宏来声明函数返回值,其原型如下:
QGenericArgument Q_ARG(Type, const Type & value)
QGenericReturnArgument Q_RETURN_ARG(Type, Type & value)
使用QObject::connect()可以连接QML中的信号,connect()共有四个重载函数,它们都是静态函数。必须使用SIGNAL()宏来声明信号,SLOT()宏声明槽函数。
使用QObject::disconnect()可以解除信号与槽函数的连接。
(1)修改main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window {
visible: true
width: ; height:
title: "Union Lotto Game"
color: "white"
signal qmlSignal(string message)
onQmlSignal: console.log("qml signal message is", message) // this is a qml signal
function qmlFunction(parameter) {
console.log("qml function parameter is", parameter) // Hello from C++
return "function from qml"
}
Rectangle {
objectName: "rect"
anchors.fill: parent
color: "yellow"
}
MouseArea {
anchors.fill: parent
onClicked: {
gemini.begin()
gemini.stop()
gemini.ballNumber =
qmlSignal("this is a qml signal")
}
}
Gemini {
id: gemini
onBegin: doSomething(Gemini.BALL_COLOR_RED)
onBallNumberChanged: console.log("new ball number is", ballNumber) // 10
Component.onCompleted: console.log("default ball number is", ballNumber) // 0
}
}
main.qml中添加了qmlSignal()信号和qmlFunction()函数,信号在QML中发送,函数在C++中调用。
(2)修改Gemini.h
#ifndef GEMINI_H
#define GEMINI_H
// Gemini.h
#include <QObject>
#include <QDebug>
class Gemini : public QObject
{
Q_OBJECT
Q_ENUMS(BALL_COLOR)
Q_PROPERTY(unsigned int ballNumber READ ballNumber WRITE setBallNumber NOTIFY ballNumberChanged)
public:
Gemini() : m_ballColor(BALL_COLOR_YELLOW), m_ballNumber() {
qDebug() << "Gemini::Gemini() called";
}
enum BALL_COLOR {
BALL_COLOR_YELLOW,
BALL_COLOR_RED,
BALL_COLOR_BLUE,
BALL_COLOR_ALL
};
unsigned int ballNumber() const {
return m_ballNumber;
}
void setBallNumber(const unsigned int &ballNumber) {
if(ballNumber != m_ballNumber) {
m_ballNumber = ballNumber;
emit ballNumberChanged();
}
}
Q_INVOKABLE void stop() {
qDebug() << "Gemini::stop() called";
}
signals:
void begin();
void ballNumberChanged();
public slots:
void doSomething(BALL_COLOR ballColor) {
qDebug() << "Gemini::doSomething() called with" << ballColor;
if(ballColor != m_ballColor) {
m_ballColor = ballColor;
qDebug() << "ball color changed";
}
}
void cppSlot(const QString &message) {
qDebug() << "Called the C++ slot with message:" << message; // this is a qml signal
}
private:
BALL_COLOR m_ballColor;
unsigned int m_ballNumber;
};
#endif // GEMINI_H
Gemini类中添加了cppSlot()槽函数,将要在main.cpp中与QML的信号connect。
(3)修改main.cpp
#include <QGuiApplication>
#include <QtQml>
#include <Gemini.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Gemini>("Union.Lotto.Gemini", , , "Gemini");
QQmlEngine engine;
// set qml context property
// Gemini aGemini;
// engine.rootContext()->setContextProperty("aGemini", &aGemini);
QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:///main.qml")));
QObject *object = component.create();
qDebug() << "width value is" << object->property("width").toInt();
object->setProperty("width", );
qDebug() << "height value is" << QQmlProperty::read(object, "height").toInt();
QQmlProperty::write(object, "height", );
QObject *rect = object->findChild<QObject*>("rect");
if(rect) {
rect->setProperty("color", "black");
}
QVariant returnedValue;
QVariant message = "Hello from C++";
QMetaObject::invokeMethod(object, "qmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, message));
qDebug() << "returnedValue is" << returnedValue.toString(); // function from qml
Gemini test;
QObject::connect(object, SIGNAL(qmlSignal(QString)),
&test, SLOT(cppSlot(QString)));
return app.exec();
}
在main.cpp中添加了QMeta::invokeMethod()和QObject::connect()来分别访问QML中函数和信号。
7、总结
本文主要介绍了QML与C++混合编程常用的方法与技巧,在使用过程中有几点值得注意:
自定义类一定要派生自QObject类或其子类。
必须使用Q_OBJECT宏。
注册自定义类到Qt元对象系统或设置自定义类对象实例为QML上下文属性是必须的。
两者交互进行数据传递时,要符合QML与C++间数据类型的转换规则。
QML与C++混合编程详解(转)的更多相关文章
- 【Qt】Qt Quick 之 QML 与 C++ 混合编程详解
Qt Quick 之 QML 与 C++ 混合编程详解 - CSDN博客 专栏:Qt Quick简明教程 - CSDN博客 .
- QML与C++混合编程详解
1.QML与C++为什么要混合编程 QML与C++为什么要混合编程,简单来说,就是使用QML高效便捷地构建UI,而C++则用来实现业务逻辑和复杂算法,下面介绍了两者间交互的方法与技巧. 2.QML访问 ...
- C51与汇编混合编程详解
C51和汇编混合编程(1)-C语言中嵌入汇编 1.在 C文件中要嵌入汇编代码片以如下方式加入汇编代码: #pragma ASM ;Assembler Code Here #pragma ENDASM ...
- ORACLE PL/SQL编程详解
ORACLE PL/SQL编程详解 编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设 ...
- Flex布局新旧混合写法详解(兼容微信)
原文链接:https://www.usblog.cc/blog/post/justzhl/Flex布局新旧混合写法详解(兼容微信) flex是个非常好用的属性,如果说有什么可以完全代替 float 和 ...
- Linux串口编程详解(转)
串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备.虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接 ...
- [强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)
原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天 ...
- [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)
原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ...
- 【强烈强烈推荐】《ORACLE PL/SQL编程详解》全原创(共八篇)--系列文章导航
原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解> 系列文章目录导航 ——通过知识共享树立个人 ...
随机推荐
- ThinkPHP5作业管理系统中处理学生未交作业与已交作业信息
在作业管理系统中,学生登陆到个人中心后可以通过左侧的菜单查看自己已经提交的作业和未提交作业.那么在系统中如何实现这些数据的查询的呢?首先我们需要弄清楚学生(Student).班级(class).作业提 ...
- Win10下Pytorch的安装和使用[斗之力三段]
简介: 看到paper的代码是用Pytorch实现的,试图理解代码,但是看不懂,只能先学一些基础教程来帮助理解.笔记本电脑配置较低,所以安装一个没有CUDA的版本就可以了.安装完之后,就可以跟着教程边 ...
- Python 3.6 爬取BD电影网
2018-07-10 #coding:utf-8 #coding:utf-8 from lxml import etree import requests import pandas import t ...
- chrome提示Adobe Flash Player过期解决
安装插件:install_flash_player_ppapi.exe
- 【集训试题】exam 信心考 最小割
题意概述: 有N个人,A,B两个考场.如果学生i在A考场,总信心值增加xi:如果学生i在B考场,总信心值增加yi.其中还有m对好友,当第i对好友的两个人都在A考场时,总信心值增加ai:如果两人都在B考 ...
- Object类中的五种方法
clone() Object类源码:protected native Object clone() throws CloneNotSupportedException; 这里有个问题:为什么Sun公司 ...
- PAT 1080 MOOC期终成绩
https://pintia.cn/problem-sets/994805260223102976/problems/994805261493977088 对于在中国大学MOOC(http://www ...
- 【EasyNetQ】- 订阅
EasyNetQ订阅者订阅消息类型(消息类的.NET类型).一旦通过调用Subscribe方法设置了对类型的订阅,就会在RabbitMQ代理上创建一个持久队列,并且该类型的任何消息都将被放置在队列中. ...
- vue2.0实现页面刷新时某个input获得focus
通过自定义指令:
- Java IO 小结
Java IO 的学习需要明白流设计的体系结构,这样才能在实际需要的时候,通过API文档查阅,快速实现功能.