日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

git 使用writer_GitHub - Vpredictor/WriterFly: [QT/C++] 写作天下,为作家创造世界而生,执云作笔,诉尽平生意。...

發布時間:2023/12/10 c/c++ 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 git 使用writer_GitHub - Vpredictor/WriterFly: [QT/C++] 写作天下,为作家创造世界而生,执云作笔,诉尽平生意。... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫作天下

簡介

為作家們創造世界而誕生,執云作筆,訴盡平生意。

集簡約UI與人性化AI于一體的碼字工具,無論是小說、作文、日記、報告,都能輕松駕馭。

QQ交流群:705849222

特點

已有功能:

自由的目錄:自動序號,導入導出

一體化界面:全局自定義主題

輸入動畫:獨創文字平滑輸入效果、光標平滑移動

智能引號:增刪移動全在一鍵之間

智能空格:縮進、標點、移動光標融為一體

智能回車:雙引號內回車、自動添加句末標點、自動縮進

自動標點:語氣詞后面自動加上標點符號

同音詞覆蓋:選詞錯誤,無需刪除,直接覆蓋舊內容

自動分段:換行/排版時,過長段落自動在合適的地方分段

自動提示:輸入時自動提示同義詞、相關詞、常用句

隨機取名:最輕便的取名方式,要啥來啥

一鍵排版:全自動

未來功能(近期繁忙,無力開發):

大綱列表

章節細綱

名片注釋

名字高亮

綜合搜索

全書替換

右下角通知卡片

自定義主題

自定義快捷鍵

小黑屋

云同步

排行榜

拼字房間

章節分享

“求評價”廣場

主角背包

快捷鍵

ctrl + ←/→ 按詞語移動

alt + ←/→ 按句子移動

ctrl + alt + ←/→ 按段落移動

ctrl + shift + ↑/↓ 擴大/縮小選擇

ctrl/alt + ↑/↓ 屏幕滾動,alt更快

空格鍵 智能空格

引號鍵 智能引號

回車鍵 智能回車

Tab鍵 句子補全+光標跳過

ctrl+T 一鍵排版

ctrl+D 句內同音詞替換(不必連續)

ctrl+F 章內文字搜索

ctrl+P 全局綜合搜索

更多快捷鍵請等待后期加入(或將支持自定義快捷鍵)

技術特點

開發環境:C++/Qt5.11.3,Qt Creator

運行環境:Windows、Android

1、標點AI

雖然是簡單暴力的枚舉(都是自己遇到的),但是有特判了上千種情況,也不容易吧……

若是人物語言描寫,還能根據人物的表情動作神態來分析情感程度,進一步提高準確度。

手動判斷,故覆蓋不全,不過在一定情況下,枚舉簡單易用,是為上上之選!

還有各種常用按鍵的自動化操作,極大程度上增加效率!

/**

* 小說語氣識別的AI類

*/

class NovelAIBase

{

/*...略了一些方法...*/

void operatorSmartSpace(); // 智能空格:按下空格觸發

void operatorSmartEnter(); // 智能回車:按下回車觸發

void operatorSmartQuotes(); // 智能引號:按下引號觸發

void operatorSmartBackspace(); // 智能刪除,按下刪除觸發

bool operatorAutoPunc(); // 自動標點:語氣詞自動觸發

bool operatorSentFinish(); // 句末標點:增加或轉化成結尾

void operatorSmartQuotes2(int left, int right); // 智能引號,僅在選中文本的情況下調用

virtual int getWordCount(QString str); // 字數統計,交給 NovelAI

QString getPunc(QString para/*段落*/, int pos/*光標*/); // ☆核心:取標點(句子)

QString getPunc(/*QString fullText, int pos*/); // 這個是全部文本中的某一部分

QString getPunc(int pos); // 全部文本,特定位置的標點

QString getPunc2(int pos); // 把","改成"。"

QString getPunc2(); // 把","改成"。"

int getDescTone(QString sent); // 句子語氣標點,影響語氣導向

QString getTalkTone(QString sent, QString sent2, int tone, QString left1, QString left2);

void updateCursorChars(); // 修改光標附近的字符

bool canDeletePairPunc(); // 是否能夠刪除成對文本(能刪就刪)

bool isCursorInQuote(QString text, int pos); // 是否在引號里面

virtual void moveCursor(int x) = 0; // 移動光標

virtual void insertText(int pos, QString text) = 0; // 插入文本

virtual void insertText(QString text) = 0; // 插入文本

virtual void deleteText(int start, int end) = 0; // 刪除文本

// bool isNextLang(); // 是否是后一句話(雙引號前面多的是逗號)

bool isSentPunc(QString str); // 是否為句末標點(不包含引號和特殊字符,不包括逗號)

bool isSentSplitPunc(QString str); // 是否為句子分割標點(包含逗號)

bool isSentSplit(QString str); // 是否為句子分割符(各類標點,包括逗號)

bool isASCIIPunc(QString str); // 是否為英文標點(不包含引號和特殊字符)

bool isBlankChar(QString str); // 是否為空白符

bool isBlankChar2(QString str); // 是否為換行之外的空白符

bool isBlankString(QString str); // 是否為空白字符串

bool isSymPairLeft(QString str); // 是否為對稱標點左邊的

bool isSymPairRight(QString str); // 是否為對稱標點右邊的

QString getSymPairLeftByRight(QString str); // 根據右邊括號獲取左邊的括號

QString getSymPairRightByLeft(QString str); // 根據右邊括號獲取左邊的括號

QString getCursorFrontSent(); // 獲取當前面的句子

QString getCurrentChar(int x); // 獲取當前位置的附近漢字

bool isQuoteColon(QString str); // 漢字后面是否需要加標點

protected:

QString _text, _pre_text; // 文本

int _pos, _pre_pos, _dif; // 光標位置和字數差

QString _left1, _left2, _left3, _right1, _right2; // 光標附近的文本

bool isInQuotes; // 是否在引號里面(用來判斷是否為語言或者描述)

private:

QString _shuo_blacklists, _dao_whitelists, _wen_blacklists; // “說”黑名單、“道”白名單、“問”黑名單

QString _symbol_pair_lefts, _symbol_pair_rights; // 成對符號左邊/右邊

QString _quote_no_colon, _quantifiers; // 引號前面沒有冒號

QString _sent_puncs, _sent_split, _sent_split_puncs, _blank_chars; // 句末標點、句子分割符、空白符

QString _auto_punc_whitelists; // 自動標點白名單

};

子類為NovelAI,再下一個子類 NovelEditor 使用到了多繼承,同時繼承 QTextEdit 與 NovelAI。

其實設計得不是很好,AI 類需要大量調用 Edit 的方法,于是加了許多虛函數,將三個類緊緊耦合到一起(不過關系不大,本來就是怕一個文件代碼太長而分開的)。

2、仿IDE思路

當今所謂的寫作軟件,單論寫作方面,其實和一個記事本沒多少差別,無非多了目錄與自動縮進,以及簡單的自動保存等。其一些亮點,比如強制寫作的小黑屋、多人競爭的在線拼字,都無法從“碼字”本身來幫助作者達到更高效的辦公,這些附加的功能甚至會讓作者分心,無法好好靜心創作。

寫作天下定位一款單純的“文學創作”編輯器,主打從“寫作”本身提高效率,弱化與文字無關的功能。或許后期將會添加小黑屋、拼字等,但絕不會將這些作為主要功能。

備注:近期繁忙,無力開發,所以只是“思路”!

一些功能:

增強的編輯功能

自動提示

面向對象寫作:名片系統

文字高亮(名片高亮)

高度個性化設置(功能細節、快捷鍵、主題等)

追求自動的編輯器

一句話:能自動的,絕不手動!

為了實現更加人性化的功能,程序中使用了大量的算法。

比如括號匹配功能,輸入左括號時自動添加右括號、刪除鍵刪除成對的符號,這里使用數據結構中的棧,判斷光標前后各自左右括號的數量,入棧出棧,來判斷是否需要添加/刪除,而不僅僅依靠光標前一個字符。

還有光標移動、在標點前面換行、在語言描寫內回車自動插入前后引號、修改引號前面的逗號與冒號等,一個按鍵,多種功能。

輕松提示

經過多種方案的性能測試,選取了速度最快、運行最穩定的方式。

以下為輸入文字后自動提示算法:

/**

* 某個句子的某個位置處進行搜索

* @param sent 欲搜索的完整句子(短句,不包含標點)

* @param cursor 光標在句子中的相對位置

* @return 是否找到

*/

bool Lexicons::surroundSearch(QString sent, int cursor)

{

int len = sent.length();

search_result.clear();

match_sentence = false;

bool find = false;

matched_key = "";

int start_pos = 0;

QString l1 = "", l2 = "", l4 = "";

if (cursor >= 1)

l1 = sent.mid(cursor-1, 1);

if (cursor >= 2)

l2 = sent.mid(cursor-2, 2);

if (cursor >= 4)

l4 = sent.mid(cursor-4, 4);

if (random_inited)

{

// 隨機種類列表

if (((matched_key = l2) == "隨機")

|| ((matched_key = l2) == "取名")

|| ((matched_key = l4) == "隨機取名"))

if (searchRandom("隨機取名"))

{

matched_case = COMPLETER_CONTENT_RAND_LIST;

return true;

}

// 姓氏

if (surname_inited && (((matched_key = l1) == "姓")

|| ((matched_key = l2) == "姓氏")))

if (searchRandom("姓氏"))

{

matched_case = COMPLETER_CONTENT_SURN;

return true;

}

// 人名

if (name_inited && (((matched_key = l2) == "人名")

|| ((matched_key = l2) == "名字")))

if (searchRandom("人名"))

{

matched_case = COMPLETER_CONTENT_NAME;

return true;

}

// 隨機列表

for (QString s : random_sort_list)

{

if (cursor >= s.length() && sent.mid(cursor-s.length(), s.length()) == s && isFileExist(lexicon_dir + "random/" + s + ".txt"))

{

matched_key = s;

matched_case = COMPLETER_CONTENT_RAND;

searchRandom(s);

return true;

}

}

}

// 搜索4個字

if (!find)

{

start_pos = 0; // 開始搜索的位置

if (start_pos < cursor-4) start_pos = cursor-4;

for (int i = start_pos; i <= len-4 && i < cursor; i++)

{

if (search(sent.mid(i, 4), true))

{

find = true;

matched_key = sent.mid(i, 4);

break;

}

}

}

// 搜索三個字

if (!find)

{

start_pos = 0;

if (start_pos < cursor-3) start_pos = cursor-3;

for (int i = start_pos; i <= len-3 && i < cursor; i++)

if (search(sent.mid(i, 3), true))

{

find = true;

matched_key = sent.mid(i, 3);

break;

}

}

// 搜索兩個字

if (!find)

{

start_pos = 0;

if (start_pos < cursor-2) start_pos = cursor-2;

for (int i = start_pos; i <= len-2 && i < cursor; i++)

if (search(sent.mid(i, 2), true))

{

find = true;

matched_key = sent.mid(i, 2);

break;

}

}

//qDebug() << "surround search:" << matched_key << " result:" << search_result;

search_last = sent;

matched_case = COMPLETER_CONTENT_WORD;

return find;

}

/**

* 在詞庫中搜索某一個詞語

* @param key 欲搜索的詞語

* @param add 是否為添加模式。如果不是,則先清空已經找到的列表

* @return 是否有搜索結果

*/

bool Lexicons::search(QString key, bool add)

{

if (key.isEmpty()) return false;

/* // 上次搜索的緩沖區,但是沒必要了,因為每次surroundSearch的時候

* // 都把上次的搜索結果清空了,key還在但是result沒了

if (key == search_last)

{

return true;

}*/

if (!add) search_result.clear();

bool find = false;

int key_len = key.length();

if (synonym_inited)

{

QStringList synonym_list;

int pos = 0;

while (1)

{

//pos = synonym_text.indexOf(key, pos);

pos = synonym_text.indexOf(QRegExp("\\b"+key+"\\b"), pos);

if (pos == -1) break;

int left = synonym_text.lastIndexOf("\n", pos)+1;

int right = synonym_text.indexOf("\n", pos);

if (right == -1) right = synonym_text.length();

QString para = synonym_text.mid(left, right-left);

QStringList list = para.split(" ", QString::SkipEmptyParts);

// TODO 后期將改成 QList

synonym_list.append(list);

pos += key_len;

find = true;

}

if (synonym_list.size() > 0 && shouldRandom())

{

if (shouldRandom())

{

std::random_shuffle(synonym_list.begin(), synonym_list.end());

}

search_result.append(synonym_list);

}

}

if (related_inited)

{

QStringList related_list;

int pos = 0;

while (1)

{

pos = related_text.indexOf(QRegExp("\\b"+key+"\\b"), pos);

if (pos == -1) break; // 找不到了

if (pos > 0 && related_text.mid(pos-1, 1) == "{") // 是標題

{

int left = related_text.indexOf("[", pos)+1;

int right = related_text.indexOf("]", pos);

if (right < left-1) // 出現了錯誤

{

pos = left+1;

continue;

}

if (right == -1) right = related_text.length();

QString para = related_text.mid(left, right-left);

QStringList list = para.split(" ", QString::SkipEmptyParts);

// TODO 后期將改成 QList

related_list.append(list);

pos = right;

}

else // 是內容

{

// 如果是本程序標準格式

int left = related_text.lastIndexOf("[", pos)+1;

int right = related_text.indexOf("]", pos);

// 如果只是一段一段分開的

int left_n = related_text.lastIndexOf("\n", pos)+1;

if (left_n >= left)

{

left = left_n;

right = related_text.indexOf("\n", pos);

}

if (right == -1) right = related_text.length();

QString para = related_text.mid(left, right-left);

QStringList list = para.split(" ", QString::SkipEmptyParts);

// TODO 后期將改成 QList

related_list.append(list);

pos = right;

}

find = true;

}

if (related_list.size() > 0)

{

if (shouldRandom())

{

std::random_shuffle(related_list.begin(), related_list.end());

}

search_result.append(related_list);

}

}

if (sentence_inited && find)

{

if (sentence_text.indexOf(key) > -1)

{

match_sentence = true;

search_result.append("-->");

}

}

//qDebug() << "search:" << key << " result:" << search_result;

return find;

}

/**

* 通過一個詞語,來獲取應該顯示的隨機取名提示列表

* @param key 欲搜索的詞語

* @return 是否找到結果

*/

bool Lexicons::searchRandom(QString key)

{

// ==== 隨機取名列表 ====

if (key == "隨機取名" || key == "隨機" || key == "取名")

{

for (QString s : random_sort_list)

search_result.append(s);

std::random_shuffle(search_result.begin(), search_result.end());

return true;

}

// ==== 隨機取名具體 ====

for (int i = 0; i < random_sort_list.size(); i++)

if (random_sort_list.at(i) == key)

{

QStringList list = random_text_list.at(i).split(" ", QString::SkipEmptyParts);

search_result = list;

std::random_shuffle(search_result.begin(), search_result.end());

search_result = search_result.mid(0, 100);

return true;

}

return false;

}

/**

* 搜索后返回結果

* @return 搜索結果

*/

QStringList Lexicons::getResult()

{

return search_result;

}

3、平滑輸入

創作,或是為了寧靜的內心,或是為了美好的生活,終是需要解放內心的壓抑。

而寫作天下的輸入動畫與平滑光標,為了打造愉悅的創作環境,可謂是嘔心瀝血。

動畫算法

輸入動畫

輸入動畫中每一個字符都是一個Label對象,設置文字顏色為對應字符,然后使用一個動畫管理器進行統一管理,開放管理器的API給編輯器,編輯文字的同時通過管理器調整所有文字的動畫,便不會出現沖突的情況。

難點在要將每個Label和對應文字連在一起,尤其是支持實時修改。看了其他相同功能的開源項目,大多只支持英文,并且是監聽到文字輸入后才開始動畫,等動畫結束再上屏,無法在輸入后立即刪除或者修改,非常影響效率。

/**

* 輸入動畫管理器類

*/

class EditorInputManager : public QObject

{

Q_OBJECT

public:

EditorInputManager();

void setEditor(QTextEdit* edit); // 設置開啟動畫對應的編輯器

void setColor(QColor color); // 設置全文顏色

void textChanged(int old_position, int diff); // 文字改變時調整動畫控件

void updateRect(int range_start, int rande_end); // 更新動畫控件的位置

void addInputAnimation(QPoint point, QString str, int position, int delay, int duration); // 添加一個文字動畫

void addInputAnimation(QPoint point, QString str, int position, int delay, int duration, QColor color); // 添加一個帶有不同顏色的文字動畫

void updateTextColor(int current_position); // 修改全文顏色,同時修改正在動畫的顏色

public slots:

void aniFinished(int position, EditorInputCharactor *); // 動畫結束,傳參文字位置

private:

QTextEdit* _edit; // 編輯器

QColor font_color; // 全文顏色

QList ani_list; // 動畫控件列表

};

/**

* 輸入動畫的某一個字符實體,存儲動畫信息、光標位置、光標坐標、光標文字等

*/

class EditorInputCharactor : public QLabel

{

Q_OBJECT

Q_PROPERTY(int fontsize READ getFontSize WRITE setFontSize RESET resetFontSize)

public:

EditorInputCharactor(QWidget* parent, QPoint point, QString str, int position, QFont font, int delay = 0, int duration = 200);

int getPosition(); // 獲取動畫的文字位置,更新位置、動畫結束文字變回原色時要用到

void changePosition(int x); // 修改動畫的位置

void updateRect(QPoint point); // 更新控件坐標

// 字體動畫接口

void setFontSize(int x);

int getFontSize();

void resetFontSize();

signals:

void aniFinished(int position, EditorInputCharactor* charactor); // 動畫結束

private:

QPoint point; // 坐標

QString str;

int position; // 文字位置

int duration; // 動畫時長,同時輸入的不同位置的文字時長不一樣

QPropertyAnimation *ani; // 動畫對象

int origin_position; // 一開始的位置

int font_size; // 文字大小動畫屬性

int font_size_l;

};

平滑光標

平滑光標添加一個矩形控件為光標樣式,每次改變時存儲其坐標,然后借助動畫移動控件。

其實還簡單,但難點在要好好控制什么時候才開始動畫,不然光標會亂飄或者閃動,看起來效果很差。

最大的難點在于,與功能“光標行固定”以及“底部光標固定”有很大的沖突,還有每次修改文字時(這是自定義事件經常使用QTextEdit.setText()方法才會出現的問題)需要大大約束光標動畫的時機。

4、MVD目錄結構

Qt標準 QListView 的MVD模型,一開始以為很難,剛走來發現其實就是重寫幾個方法。

這里使用的 MVD似乎與標準的不太一樣,看下去就知道了。

Model

由于寫作天下的目錄比較復雜,所以專門寫了一個類NovelDirMData來存放多個NovelDirItem的信息。

此處 Model 用到了多繼承,以及友元。(其實這個模型已經變了味了)

class NovelDirModel : public QAbstractListModel, public NovelDirMData

{

/*...其余代碼略...*/

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const

{

// 不需要 index 的 data

if (role == Qt::UserRole+DRole_ROLL_COUNT)

{

return roll_subs.size();

}

else if (role == Qt::UserRole+DRole_CR_COUNT)

{

return cr_list.size();

}

else if (role == Qt::UserRole+DRole_ROLL_NAMES)

{

return roll_names;

}

// 判斷 index

if ((!index.isValid()) || (index.row() >= cr_list.size()))

return QVariant();

NovelDirItem item = cr_list.at(index.row());

if (role == Qt::UserRole+DRole_CHP_NAME)

{

return item.getName(); // 章節名

}

else if (role == Qt::UserRole+DRole_CHP_NUM)

{

return item.getNumber(); // 序號

}

else if (role == Qt::UserRole+DRole_CHP_NUM_CN)

{

return item.getNumber_cn(); // 序號

}

else if (role == Qt::UserRole+DRole_CHP_ROLLINDEX)

{

return item.getRollIndex(); // 序號

}

else if (role == Qt::UserRole+DRole_CHP_CHPTINDEX)

{

return item.getChptIndex(); // 序號

}

else if (role == Qt::UserRole+DRole_CHP_DETAIL)

{

return item.getDetail(); // 細綱

}

else if (role == Qt::UserRole+DRole_CHP_OPENING)

{

return item.isOpening(); // 是否編輯中

}

else if (role == Qt::UserRole+DRole_CHP_ISROLL)

{

return item.isRoll(); // 是否為分卷

}

else if (role == Qt::UserRole+DRole_CHP_ISHIDE)

{

return item.isHide(); // 是否隱藏

}

else if (role == Qt::UserRole+DRole_CHP_STEMP)

{

return item.getS_temp(); // 雙擊編輯,出錯后恢復原來的文本

}

else if (role == Qt::UserRole+DRole_ROLL_SUBS)

{

int rIndex = item.getRollIndex();

return roll_subs[rIndex]; // 分卷章數量

}

else if (role == Qt::UserRole+DRole_ROLL_COUNT)

{

return roll_subs.size();

}

else if (role == Qt::UserRole+DRole_CR_COUNT)

{

return cr_list.size();

}

else if (role == Qt::UserRole+DRole_CHP_FULLNAME)

{

return item.getFullChapterName();

}

else if (role == Qt::UserRole+DRole_RC_ANIMATING)

{

return item.isAnimating();

}

else if (role == Qt::UserRole+DRole_ROLL_NAMES)

{

return roll_names;

}

else if (role == Qt::UserRole+DRole_RC_SELECTING)

{

return item.isSelecting();

}

return QVariant();

}

// 重寫 flags 和 setData 使 Model 可雙擊編輯

Qt::ItemFlags flags(const QModelIndex &index) const

{

Qt::ItemFlags flags = QAbstractItemModel::flags(index);

//if (index.row() > 0 && us->one_click) // 作品相關卷名不允許更改

//flags |= Qt::ItemIsEditable;

if (index.row() > 0)

flags |= Qt::ItemIsEditable;

return flags;

}

bool setData(const QModelIndex &index, const QVariant &value, int role)

{

if (!index.isValid()) return false;

NovelDirItem item = cr_list.at(index.row());

if (role == Qt::EditRole) // 修改章節名

{

QString old_name = item.getName();

bool isNew = false;

if (canRegExp(old_name, "新[章卷]\\d+")) // 分卷是聚集焦點用

isNew = true;

bool rst = tryChangeName(index.row(), value.toString());

if (/*isNew && */rst) // 重命名成功

{

if (isNew) // 如果是新建的

emit signalOpenChapter(index.row());

else // 否則就是重命名,修改已經打開的舊名字標簽頁

emit signalChangeFullName(novel_name, value.toString());

}

return rst;

}

else if (role == Qt::UserRole+DRole_CHP_STEMP)

{

cr_list[index.row()].setS_temp(value.toString());

}

else if (role == Qt::UserRole+DRole_CHP_FULLNAME)

{

cr_list[index.row()].setFullChapterName(value.toString());

deb(value.toString(), "model.setFullChapterName");

}

return true;

}

}

View

這里重寫的方法有點多……就放一個設置Model和Delegate的。

不是很標準,因為為了方便,把應該解耦的Model和Delegate都聲明為成員變量了。

// 設置 delegate

novel_dir_delegate = new NovelDirDelegate(this);

setItemDelegate(novel_dir_delegate);

// 設置 model

novel_dir_model = new NovelDirModel(this);

setModel(novel_dir_model);

Delegate

因為用到了作品設置,有用戶自定義的完全不同的目錄結構,所以和Model一樣使用了多繼承。

有三大特色:

用戶自定義文字顯示:例如,阿拉伯數字自動排序、不顯示分卷等

圓形顯示效果:不知道該怎么描述……至少要比默認的藍色選中效果好看吧?

支持全局主題色/點綴色,實時修改

/**

* 目錄列表代理類

*/

class NovelDirDelegate : public QItemDelegate, public NovelDirSettings

{

/* ... 略了一些 ... */

QString getItemText(const QModelIndex &index) const

{ /*...獲取章節序號,略...*/}

void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const

{

QStyleOptionViewItem op(option);

op.palette.setColor(QPalette::Highlight, us->getOpacityColor(us->accent_color, 128));

painter->save();

// 獲取文字

QString text= getItemText(index);

int deviate = DIR_DEVIATE; // 初始偏移位置

int subs = -1; // 分卷數量,章節為-1

if (index.data(Qt::UserRole+DRole_CHP_ISROLL).toBool()) // 是分卷,畫數字

{

subs = index.data(Qt::UserRole+DRole_ROLL_SUBS).toInt();

}

else // 是章節

{

if (isNoRoll() && index.data(Qt::UserRole+DRole_CHP_NUM).toInt() > 0) // 不顯示分卷 且 是正文,則取消縮進

;

else

deviate += DIR_DEVIATE_ADD; // 增加章節的縮進

}

// 獲取文字區域并繪制

QFontMetrics fm(painter->font());

QRect text_rect = QRect(op.rect.topLeft()+QPoint(deviate,(op.decorationSize.height()+us->mainwin_sidebar_spacing*2-fm.height())/2),QSize(fm.width(text),fm.height()));

if (!us->round_view)

drawBackground(painter, op, index); // 畫選中的顏色的(不加這行的話就是透明選中)

// 先繪制背景

if (!index.data(Qt::UserRole+DRole_RC_ANIMATING).toBool()) // 不是在動畫中(動畫時不顯示文字,即背景透明)

{

// 繪制選中狀態的紙片形狀背景

if (us->round_view && (option.state & QStyle::State_Selected))

{

int text_padding = text_rect.height()/2-1;

QColor bg_color = us->getOpacityColor(us->accent_color, 128);

QRect round_rect(text_rect.left()-text_padding, text_rect.top()-3, text_rect.width()+text_padding*2, text_rect.height()+6);

painter->setRenderHint(QPainter::Antialiasing);

QPen pen(bg_color, Qt::NoPen);

painter->setPen(pen);

QPainterPath path;

int radius = round_rect.height()/2-1;

path.addRoundedRect(round_rect, radius, radius);

painter->fillPath(path, bg_color);

painter->drawPath(path);

painter->setRenderHint(QPainter::Antialiasing, false);

}

// 繪制文字

if (isNoRoll() && subs >= 0) // 不使用分卷,并且剛好是分卷,則使用灰色,弱化分卷存在感

{

painter->setPen(QColor(128, 128, 128));

}

else

painter->setPen(QColor(0, 0, 0));

painter->drawText(text_rect, text);

// 畫左邊的小標記

if (subs >= 0) // 是分卷(章節默認 -1)

{

}

else // 是章節,繪制打開狀態

{

if (index.data(Qt::UserRole+DRole_CHP_OPENING).toBool()) // 打開狀態中,畫右邊的小點

{

QRect state_rect = QRect(op.rect.topLeft()+QPoint(0,1),QSize(1,op.rect.height()-2));

painter->setPen(QPen(QColor(us->accent_color), Qt::SolidLine));

painter->setBrush(QBrush(QColor(us->accent_color), Qt::SolidPattern));

painter->drawRect(state_rect);

}

}

// 畫右邊的小標記,分卷數量

if (subs >= 0) // 是分卷(章節默認 -1)

{

if (subs == 0) // 沒有章節,灰色的數字

{

painter->setPen(QColor(128, 128, 128));

}

else // 章節,黑偏灰色的

{

painter->setPen(QColor(64, 64, 64));

}

QString subs_text = QString("%1").arg(subs);

QRect display_rect2 = QRect(op.rect.topRight()-QPoint(fm.width(subs_text)+10,-3),QSize(fm.width(subs_text),fm.height()));

painter->drawText(display_rect2, subs_text);

}

}

// drawFocus(painter, option, displayRect); // 畫選區虛線

drawFocus(painter, op, QRect(0, 0, 0, 0));

painter->restore();

}

QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const

{

Q_UNUSED(index);

//QSize size = option.rect.size(); // 這個是整個QListView的矩形……

QSize size = option.decorationSize;

size.setHeight(size.height()+us->mainwin_sidebar_spacing*2);

return size;//QItemDelegate::sizeHint(o2, index);

}

/* 編輯框修改名字 */

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex&index) const

{

Q_UNUSED(option);

Q_UNUSED(index);

QLineEdit* edit = new QLineEdit(parent);

edit->setAcceptDrops(false);

QString style = "";//"background-color:"+us->getColorString(us->accent_color)+";";

if (us->round_view)

{

QString text= getItemText(index);

QFontMetrics fm(edit->font());

int r = fm.height()/2;

QString rs = QString("%1").arg(r);

style += "border:1px;border-radius:"+rs+"px; padding-left: "+rs+"px;";

}

else

style += "border:none;";

edit->setStyleSheet(style);

QPalette palette = edit->palette();

if (us->editor_font_color.alpha() > 0)

palette.setColor(QPalette::Text, us->editor_font_color);

palette.setColor(QPalette::Base, us->accent_color/*editor_bg_color*/);

if (us->editor_font_selection.alpha() > 0)

palette.setColor(QPalette::HighlightedText, us->editor_font_selection);

palette.setColor(QPalette::Highlight, us->editor_bg_selection);

edit->setPalette(palette);

return edit;

}

void setEditorData(QWidget *editor, const QModelIndex &index) const

{

QString name = index.data(Qt::UserRole+DRole_CHP_NAME).toString();

if (index.data(Qt::UserRole+DRole_CHP_STEMP).toString() != "")

name = index.data(Qt::UserRole+DRole_CHP_STEMP).toString();

QLineEdit* edit = static_cast(editor);

// renameEdit = edit;

edit->setText(name);

}

void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const

{

QLineEdit* edit = static_cast(editor);

QString str = edit->text();

//closeEditor(edit, QAbstractItemDelegate::NoHint);

if (model->setData(index, str))

model->setData(index, str, Qt::UserRole+DRole_CHP_STEMP);

else

model->setData(index, str, Qt::UserRole+DRole_CHP_STEMP);

}

void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const

{

Q_UNUSED(index);

int deviate = DIR_DEVIATE-2;

if (!(index.data(Qt::UserRole+DRole_CHP_ISROLL).toBool()))

deviate += DIR_DEVIATE_ADD;

if (us->round_view)

{

QString text= getItemText(index);

QFontMetrics fm(editor->font());

int delta = fm.height()/2;

deviate -= delta;

}

QRect rect = option.rect;

rect.setLeft(rect.left()+deviate);

editor->setGeometry(rect);

}

QLineEdit* getEditor()

{

return rename_edit;

}

private :

QLineEdit* rename_edit;

};

使用這個代理后,發現效果還是挺好看的,比原先不知道好了多少。

總結

以上是生活随笔為你收集整理的git 使用writer_GitHub - Vpredictor/WriterFly: [QT/C++] 写作天下,为作家创造世界而生,执云作笔,诉尽平生意。...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。