{"id":21703303,"url":"https://github.com/xmuli/bubblechat","last_synced_at":"2025-05-12T23:24:30.768Z","repository":{"id":176242663,"uuid":"653582489","full_name":"XMuli/BubbleChat","owner":"XMuli","description":"A bubble chat message display that is adaptive in size. | 气泡聊天的消息展示的效果，且自适应大小。","archived":false,"fork":false,"pushed_at":"2025-02-28T11:51:46.000Z","size":5156,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-01T04:41:30.838Z","etag":null,"topics":["bubble","bubblechat","chat","cross-platform","qlistwidget","qt"],"latest_commit_sha":null,"homepage":"http://thinkymate.xmuli.tech","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/XMuli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-14T10:25:43.000Z","updated_at":"2025-03-29T05:38:01.000Z","dependencies_parsed_at":"2023-12-25T17:47:30.596Z","dependency_job_id":"d0f5eacf-ccc6-4729-a34b-9e566058fda6","html_url":"https://github.com/XMuli/BubbleChat","commit_stats":null,"previous_names":["xmuli/bubblemessage"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMuli%2FBubbleChat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMuli%2FBubbleChat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMuli%2FBubbleChat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XMuli%2FBubbleChat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/XMuli","download_url":"https://codeload.github.com/XMuli/BubbleChat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253838693,"owners_count":21972200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bubble","bubblechat","chat","cross-platform","qlistwidget","qt"],"created_at":"2024-11-25T21:30:38.023Z","updated_at":"2025-05-12T23:24:30.759Z","avatar_url":"https://github.com/XMuli.png","language":"HTML","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cp\u003e\n    \u003cbr/\u003e\n    \u003ch1\u003eBubbleChat\u003c/h1\u003e\n    \u003ch4\u003eA bubble chat message display that is adaptive in size\u003c/h4\u003e\n    \u003ch4\u003e气泡聊天的消息展示的效果，且自适应大小\u003c/h4\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cp align=\"right\"\u003e\u003cbr\u003e\u003ca href=\"https://thinkymate.xmuli.tech/\"\u003eEnglish\u003c/a\u003e | \u003ca href=\"https://github.com/XMuli/BubbleChat/blob/master/README.zh_CN.md\"\u003e简体中文\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\n\n## Bubble ChatChat\n\nA control for bubble chat window messages created using QListWidget and adapts to the size of the bubble.\n\nAdaptive Size\n- Bubble messages append text content and the height is automatically recalculated\n- Stretch to change the size of the main window, the width and height are automatically recalculated\n\n\n\nA bubble chat window message control created with QListWidget and with the ability to adapt the size of the bubbles.\n\nAdaptive size\n\n- Add text to the bubble message, the height will be automatically recalculated.\n- Stretch to change the size of the main window, the width and height will be automatically recalculated.\n\n\n\n## Demonstration effect\n\n\u003cimg src=\"https://fastly.jsdelivr.net/gh/XMuli/xmuliPic@pic/2023/demonstrate.gif\" width=\"100%\"/\u003e\n\n\n\n\n\n##### [Fundamental Issue]\n\nHow to eliminate that magic number through calculation for an elegant and perfect display;\n\n- Whether adding that magic number in BubbleHistory::addBubble or in Bubble::initUI(), essentially there is no difference between the two.\n- Changed the connection from\n   `connect(ui-\u003etextBrowser-\u003edocument(), \u0026QTextDocument::contentsChanged`\n   to\n   `connect(ui-\u003etextBrowser, \u0026QTextBrowser::textChanged`\n   so that even the initial assignment can be captured.\n\n##### [Existing Three Approaches]\n\n**Background**: Before the textBrowser/Bubble is displayed, we need to obtain its height; there are three approaches to calculating the height.\n\n1. Obtain it through the scrollbar; however, a single line’s value should be around 24, but here it is actually 10, thus requiring a magic number adjustment.\n\n   ```cpp\n   const auto\u0026 scrollBar = ui-\u003etextBrowser-\u003everticalScrollBar();\n   int height = scrollBar-\u003emaximum() - scrollBar-\u003eminimum() + scrollBar-\u003epageStep();\n   ```\n\n2. Given that the text is already known at this point, we can use QFontMetrics to obtain the total width of the string, divide it by the width that can be displayed in a single line (which is unknown—a pain point), thereby determining the number of lines, and then multiply by fm.lineSpacing() to get the actual height. **If the control is already displayed at that point, this is the best display solution.**\n\n   ```cpp\n   const auto\u0026 textBrowser = ui-\u003etextBrowser;\n   const QString\u0026 text = textBrowser-\u003etoPlainText();\n   int allRowCount = 0;\n   int i = 1;\n   \n   QFontMetrics fm(textBrowser-\u003efont());\n   int maxWidth = textBrowser-\u003esize().width();\n   \n   for (const QString\u0026 line : text.split('\\n')) {\n       int lineWidth = fm.horizontalAdvance(line);\n       int realRowCount = static_cast\u003cint\u003e(lineWidth / maxWidth) + 1;\n       allRowCount += realRowCount;\n       qDebug() \u003c\u003c \"i:\" \u003c\u003c i++ \u003c\u003c \"  lineWidth:\" \u003c\u003c lineWidth \u003c\u003c\"  realRowCount:\" \u003c\u003c realRowCount \u003c\u003c \"  allRowCount:\" \u003c\u003c allRowCount \u003c\u003c \"  line:\" \u003c\u003c line;\n   }\n   \n   int height = allRowCount * fm.lineSpacing();  // Optimum practical row height\n   \n   // If it's a QTextBrower or something like that, remember to add the margins.\n   // const auto h1 = textBrowser-\u003econtentsMargins().top() * 2;\n   // const auto h2 = textBrowser-\u003edocument()-\u003edocumentMargin() * 2;\n   // height = height + h1 + h2；\n   ```\n\n\n\n3. With textBrowser-\u003edocument()-\u003esize() as the actual height, the document-\u003esize() in this is actually on the small side as well, and also starts out at 0;\n\n   ```cpp\n   ui-\u003etextBrowser-\u003esetFixedHeight(document-\u003esize().height()+20);\n   emit sigChangedHeight(ui-\u003etextBrowser-\u003eheight()+56);\n   ```\n   \n   \n   \n4. Remember that there is a function that can refresh the size, but the form does not display; the implementation of a more elegant; function name forgotten not found\n\n   \n\n\n\n##### [Solution]\n\nWhen Bubble append text, at this time belongs to the already displayed, you can get its actual width and height, and then through the “tried and true method two” to calculate the height of the inside details, and then combined with the height of the (Bubble - textBrowser), ** reset the height of the outside of the QListWidgetItem's height **, finally, perfect display effect!\n\n\n\n## Who uses this program?\n\n\u003e [http://thinkymate.xmuli.tech/](http://thinkymate.xmuli.tech/)\n\n\n\n\u003cdiv align=\"center\"\u003e\n  \u003cp\u003e\n      \u003ch1\u003e\n      \u003ca href=\"https://thinkymate.xmuli.tech\"\u003e\n          \u003cimg src=\"https://fastly.jsdelivr.net/gh/XMuli/xmuliPic@pic/2023/202312180312618.png\" width=\"100%\" alt=\"ThinkyMate\"/\u003e\n      \u003c/a\u003e\n    \u003c/h1\u003e\n    \u003cbr/\u003e\n    \u003ch4\u003eSimple and easy to use desktop application for ChatGPT \u0026 AI\u003c/h4\u003e\n    \u003ch4\u003e简洁且易用的 ChatGPT \u0026 AI 的桌面应用程序\u003c/h4\u003e\n    \u003ch4\u003e簡潔且易用的 ChatGPT \u0026 AI 的桌面應用程序\u003c/h4\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cp align=\"right\"\u003e\u003cbr\u003e\u003ca href=\"https://thinkymate.xmuli.tech/\"\u003eEnglish\u003c/a\u003e | \u003ca href=\"https://github.com/XMuli/ThinkyMate/blob/master/docs/index.zh_CN.md\"\u003e简体中文\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\n\n\n\u003cbr\u003e\n\n## Contribution\n\nIf this has helped you or you find it useful, please consider clicking the **⭐ Star** and **🍴 Fork** icons of this project to show your support with a simple gesture. It’s a small way to leave a positive impression—and then, why not enjoy an iced can of your favorite soda?\n\n\n\n\n\u003cbr\u003e\n\n## Tutorial Series\n\n[QtExamples](https://github.com/XMuli/QtExamples)     Welcome `star` ⭐ and `fork` 🍴 to this series of `C++ / QT / DTK` studies, with a catalog of studies from the beginning to the end!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmuli%2Fbubblechat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxmuli%2Fbubblechat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmuli%2Fbubblechat/lists"}