qdtroy / duilib_ultimate Goto Github PK
View Code? Open in Web Editor NEWduilib 旗舰版-高分屏、多语言、样式表、资源管理器、异形窗口、窗口阴影、简单动画
Home Page: https://blog.csdn.net/duisharp?f=github
License: MIT License
duilib 旗舰版-高分屏、多语言、样式表、资源管理器、异形窗口、窗口阴影、简单动画
Home Page: https://blog.csdn.net/duisharp?f=github
License: MIT License
FadeButton 用作窗口最大化按钮的时候,偶尔点击后,状态不对,显示的是滑入的状态
duidemo 的 主界面类重写了 OnSysCommand,工作正常。
不重写的话,会导致问题:界面最大化后再最小话,点击任务栏图标,界面无法恢复到最大化状态,而且也无法再最大化。
auto i_container = static_cast<CHorizontalLayoutUI*>(m_pm.FindControl(L"test_container"));
auto i_button = new DuiLib::CButtonUI();
i_button->SetName(L"btnSearch");
i_button->SetMaxWidth(100); // 设置宽
i_button->SetMaxHeight(50); // 设置高
i_button->SetPos(CRect(80, 100, 0, 0)); // 无效
SIZE i_size;
i_size.cx = 100;
i_size.cy = 100;
i_button->Move(i_size); // 无效
i_button->SetNormalImage(L"file='oneclick.png'");
i_button->SetHotImage(L"file='oneclick_dis.png'");
i_button->SetPushedImage(L"file='overwrite.png'");
i_container->Add(i_button);
auto i_container = static_cast<CHorizontalLayoutUI*>(m_pm.FindControl(L"test_container"));
auto i_button = new DuiLib::CButtonUI();
i_button->SetName(L"btnSearch");
i_button->SetFixedWidth(100);
i_button->SetFixedHeight(50); // 配合move函数
//i_button->SetPos(CRect(80, 80, 80, 80)); // 无效
i_button->SetFloat(true); //配合move函数
SIZE i_size;
i_size.cx = 100;
i_size.cy = 50;
i_button->Move(i_size); // 有效
i_button->SetNormalImage(L"file='oneclick.png'");
i_button->SetHotImage(L"file='oneclick_dis.png'");
i_button->SetPushedImage(L"file='overwrite.png'");
i_container->Add(i_button);
当tooltips字数超过300时存在闪烁现象,超过500字符时闪烁的已经来不及看清tooltips上面显示的文字。
当Combo处于禁用状态时,鼠标悬停在combo控件上,然后滚动鼠标滚轮,滚动完之后将鼠标移开,这时候combo控件的文字就会消失(空白)。
看起来DuiLib_Ultimate确实比DuiLib好一点。改了一些bug~,点赞DuiLib_Ultimate
如果窗口bktrans=“true”,控件显示错误,下面变空。
UIMenu一些修改:
UIMenu.h
CControlUI* getHover()const{ return m_pHover; }
void setHover(CControlUI* pHover){ m_pHover = pHover; }
CControlUI* m_pHover; //用来记录当前菜单属于谁弹出
UIMenu.cpp
m_pHover(nullptr) //初始化
BOOL CMenuWnd::Receive(ContextMenuParam param)
{
.....
OnClose();
m_pHover = nullptr;//窗体销毁将赋值空
....
}
case WM_KILLFOCUS:
case WM_MOUSELEAVE: //移除窗体外,自动删除
lRes = OnKillFocus(uMsg, wParam, lParam, bHandled);
实现:
HoverMenu* m_pHoverMenu;
LRESULT CMainFrame::OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
CControlUI* pHover = m_PaintManager.FindControl(pt);
auto pMenu = m_pHoverMenu->getMenu();
bool bCreateMenu = false;
CDuiPoint point;
if (pMenu&&pHover != pMenu->getHover())
{
if (pMenu->getHover())//菜单窗体还在 现在需要手动销毁窗体
{
ContextMenuParam param;
param.wParam = 1;
pMenu->Receive(param);//销毁菜单窗体 还不能delete
}
m_pHoverMenu->deleteMenu(m_pHoverMenu->getNextMenu());//删除下一个菜单对象
pMenu = m_pHoverMenu->createMenu();//刚刚销毁窗体的菜单对象现在又是pMenu的下一个
RECT rect = pHover->GetPos();
point.x = rect.left;
point.y = rect.bottom;
ClientToScreen(m_PaintManager.GetPaintWindow(), &point);
bCreateMenu = true;
}
if (bCreateMenu)
{
DuiLib::CDuiString menuxml;
if (pHover == m_pMenuTest)
{
menuxml = _T("MenuTest.xml");
}
if (!menuxml.IsEmpty())
{
pMenu->Init(NULL, menuxml.GetData(), point, &m_PaintManager, &m_pMenuCheckInfo);
pMenu->ResizeMenu();
pMenu->setHover(pHover);
}
}
bHandled = FALSE;
return 0;
}
HoverMenu.h
using namespace DuiLib;
typedef struct _node
{
DuiLib::CMenuWnd* pMenu;
_node* next;
}Node;
/*
* 两个节点的循环链表
* 鼠标悬浮控件的菜单在WM_MOUSEHOVER消息创建和销毁
* 手动销毁窗体的时候不能立即delete对象,所以需要new一个菜单对象
* 在使用另外一个节点的时候 首先delete菜单对象,因为此时窗体早已自动销毁或者该菜单还没有创建过窗体
*/
class HoverMenu
{
public:
HoverMenu();
~HoverMenu();
DuiLib::CMenuWnd* getMenu();
DuiLib::CMenuWnd* getNextMenu();
void deleteMenu(DuiLib::CMenuWnd* pMenu);
DuiLib::CMenuWnd* createMenu();
void Clear();
private:
Node* m_pNode;
};
HoverMenu.cpp
HoverMenu::HoverMenu()
{
m_pNode = new Node;
m_pNode->pMenu = new DuiLib::CMenuWnd;
auto pnode = new Node;
pnode->pMenu = new DuiLib::CMenuWnd;
m_pNode->next = pnode;
pnode->next = m_pNode;
}
HoverMenu::~HoverMenu()
{
}
DuiLib::CMenuWnd* HoverMenu::getMenu()
{
return m_pNode->pMenu;
}
DuiLib::CMenuWnd* HoverMenu::getNextMenu()
{
DuiLib::CMenuWnd* pMemu = nullptr;
if (m_pNode&&m_pNode->next)
{
pMemu = m_pNode->next->pMenu;
m_pNode = m_pNode->next;
}
return pMemu;
}
void HoverMenu::deleteMenu(DuiLib::CMenuWnd* pMenu)
{
if (m_pNode->pMenu == pMenu&&pMenu != nullptr)
{
m_pNode = m_pNode->next;
m_pNode->next->pMenu = nullptr;
delete pMenu;
}
else if (pMenu)
{
delete pMenu;
}
}
DuiLib::CMenuWnd* HoverMenu::createMenu()
{
DuiLib::CMenuWnd* pMemu = nullptr;
if (m_pNode->next&&m_pNode->next->pMenu == nullptr)
{
m_pNode = m_pNode->next;
pMemu = m_pNode->pMenu = new DuiLib::CMenuWnd;
}
return pMemu;
}
void HoverMenu::Clear()
{
if (m_pNode)
{
if (m_pNode->pMenu)
{
delete m_pNode->pMenu;
m_pNode->pMenu = nullptr;
}
auto pnode = m_pNode->next;
delete m_pNode;
m_pNode = nullptr;
if (pnode)
{
if (pnode->pMenu)
{
delete pnode->pMenu;
}
delete pnode;
}
}
}
如题,disable 滑动条时,滑动条和滑块的图片切换为disable的状态图片。
某些场合需要提示用户某个滑动条是禁用的。
当Label控件的align设置为left,valign设置为center时没有效果。
之前使用DuiLib_Redrain维护的库时没问题,然后换成现在这个库出现布局混乱现象才发现valign属性设置无效。
组合框Combo中的项较多时,在选择较下方的项后,重新点开组合框无法定位到之前选择的位置;需要使用滚动条下拉才能找到
项目设置:警告等级4(/W4) 将警告视为错误 是(/wx)
目前在UIDefine.h添加warning块解决的
#pragma warning(push)
#pragma warning(disable : 4121)
...
#pragma warning(pop)
用duidemo程序测试,在外接显示器上点击标题栏上的最大化按钮后,窗体只有一部分显示在了两个显示器的中间位置
同一类成员指针pFn用&pFn得到的void_地址可能不同,请教原因?加入int_中间转换则ok。
正常DUILIB版本下不会碰到这个BUG,我是扩展了事件源的使用(带条件判断的委托调用),才碰到这个bug的。
`template <class O, class T>
class CDelegate : public CDelegateBase
{
typedef bool (T::* Fn)(void_);
public:
// 不同调用情况下,同一pFn用&pFn得到的void_可能不同;原因未知
//CDelegate(O* pObj, Fn pFn) : CDelegateBase(pObj, (void* )(&pFn)), m_pFn(pFn) { }
CDelegate(O* pObj, Fn pFn) : CDelegateBase(pObj, (void* )(* ((int* )((void* )&pFn)))), m_pFn(pFn) { }
CDelegate(const CDelegate& rhs) : CDelegateBase(rhs) { m_pFn = rhs.m_pFn; }
virtual CDelegateBase* Copy() const { return new CDelegate(*this); }
protected:
virtual bool Invoke(void* param)
{
O* pObject = (O_) GetObject();
return (pObject->_m_pFn)(param);
}
private:
Fn m_pFn;
};`
问下高手,a.xml窗口嵌套b.xml窗口,然后再在子窗口里面嵌套c.xml窗口。我在a窗口的windowinit事件中加载b.xml,这时候成功,代码大致如下container->Add (builder.Create (_T ("b.xml"), (UINT) 0, this, &m_pm));
这时候加载到主窗口了,然后再在子窗口里面加载c.xml,这时候爆了一个错误,主要地方大概在UIMarkup.cpp里面的下面这段代码中:
CMarkup::XMLELEMENT* CMarkup::_ReserveElement()
{
if( m_nElements == 0 ) m_nReservedElements = 0;
if( m_nElements >= m_nReservedElements ) {
m_nReservedElements += (m_nReservedElements / 2) + 500;
m_pElements = static_cast<XMLELEMENT*>(realloc(m_pElements, m_nReservedElements * sizeof(XMLELEMENT)));
}
return &m_pElements[m_nElements++];
}
m_nElements这个的值为20,m_nReservedElements这个的值为500,m_pElements的值为NULL,因为是取地址符的原因结果神奇的没报错,错误地点在其他离得比较远的地方,断点调试了一会才发现这个问题。这个代码如何解决呢?
button的tooltip设置了没有显示,还有鼠标在button悬停时鼠标还是正常状态,没有变成小手
项目需要支持多国语言,官方 duilib 支持,但又有其他不少bug,用起来比较纠结
当菜单项包含子菜单时,这时候菜单项有设置tooltips属性,子菜单也设置了tooltips属性,如果子菜单的菜单项的坐标跟主菜单的菜单项的坐标重叠(子菜单的菜单项坐标假设为20,20,主菜单的菜单项坐标假设也为20,20),这时候弹出的tooltips是子菜单的而非主菜单的。
Duilib提供的MVC架构,让C++ 的界面编程变得非常简单轻松.
但是现在的应用都不再是一个孤立的app,单纯的本地功能已经远远无法满足需求.
本地应用+webkit 的组合模式已经成为一种主流趋势
本地应用胜在实时性和效率上,对于本地文件操作和高性能显示依旧具备优势
web则胜在大数据量的处理和高度灵活的复杂界面处理.
虽然知道duilib提供 activeX 这类插件, 但是IE 的渲染性能和对HTML5的支持已经远无法达到要求.
强烈建议duilib能够提供 cef这类巨无霸的支持. 本地应用开发更加简单
为什么所有的ui的name属性,最后都会转成小写?
内存泄露严重
动态菜单弹出来后,鼠标悬停到某一个菜单项的时候,按下鼠标左键(不松开鼠标左键),鼠标往下移动,滑动到下个菜单项的时候松开鼠标左键,这时候响应的菜单时间是鼠标按下去的时候的菜单项的,而非鼠标指针所在位置的菜单项的。
建议的方法:
1.鼠标释放的时候判断下是不是按下时所记录的菜单项,不是的话就不需要响应菜单事件了。
2.鼠标释放的时候在转发菜单时间的时候转发鼠标指针所在菜单项的,而非鼠标左键按下时的菜单项的。
Debug模式一个普通窗口再弹出一个模态窗口,模态窗口中的RichEdit如果在显示出来的时候进行剪切操作,当窗口关闭时就会报错。本来以为是撤销缓冲区有数据导致的,后来在窗口关闭前清空撤销缓冲区,发现还是报错。
TDrawInfo缓存,在duilib加载大量图片资源的时候,内存会飙涨(例如IM聊天列表用户头像,在用户特别多的时候)
if (CMenuWnd::GetGlobalContextMenuObserver().GetManager() != NULL) { CMenuWnd::SetClickedMenuName(GetName()); PostMessage(CMenuWnd::GetGlobalContextMenuObserver().GetManager()->GetPaintWindow(), WM_MENUCLICK, NULL, (LPARAM)(GetChecked() ? TRUE : FALSE)); }
这里的菜单项点击之后无法获得相应的信息
1下载之后,打开Duilib.sln,提示缺少Mfcapp还有TroyControl工程项。
2编译完毕之后,运行demo,有的demo无法运行。
目前我是自己改了一下 CControlUI 的代码, 仿照 GetText() ,在 GetToolTip() 判断一下resourcetext 属性。
发现该方法有些问题。成功加载图片后,该条件不会被执行
if(!pImg || pImg->GetLastStatus() != Gdiplus::Ok)
{
pStm->Release();
::GlobalUnlock(hMem);
return 0;
}
所以也就无法释放资源,建议把pStm和hMem设置为该对象的一个私有变量,DeleteGif()中释放
Gdiplus::Image* CGifAnimUI::LoadGifFromMemory( LPVOID pBuf,size_t dwSize )
{
HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, dwSize);
BYTE* pMem = (BYTE*)::GlobalLock(hMem);
memcpy(pMem, pBuf, dwSize);
IStream* pStm = NULL;
::CreateStreamOnHGlobal(hMem, TRUE, &pStm);
Gdiplus::Image *pImg = Gdiplus::Image::FromStream(pStm);
if(!pImg || pImg->GetLastStatus() != Gdiplus::Ok)
{
pStm->Release();
::GlobalUnlock(hMem);
return 0;
}
return pImg;
}
菜单控件弹出后会获取窗口焦点,当失去焦点的时候菜单消失。如果这个菜单控件是输入框的右键菜单的话,点击右键菜单,输入框焦点就消失了,选中的文本就变灰了,跟系统的菜单行为不一致。
if( ::GetKeyState(VK_RBUTTON) < 0 ) uState |= MK_LBUTTON;
if( ::GetKeyState(VK_LBUTTON) < 0 ) uState |= MK_RBUTTON;
目前我自己在LRESULT CEditWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)下增加了以下代码实现的粘贴消息转发
else if (uMsg == WM_PASTE)
{
bHandled = FALSE;
if (m_bInit)
{
if (m_pOwner != NULL)
{
bool handled = false;
if (m_pOwner->GetName().Find(_T("bHandled")) > 0)
{
//当name内包含_bHandled_时在转发粘贴消息
handled = true;
}
if (handled)
{
//记录下编辑框的窗口句柄
HWND hwnd = m_pOwner->m_pWindow->m_hWnd;
//转发编辑框粘贴消息
m_pOwner->GetManager()->SendNotify(m_pOwner, _T("edit_paste"));
//当编辑框的窗口句柄失去焦点后也就是窗口句柄无效时就需要拦截粘贴消息
if (!::IsWindow(hwnd))
{
bHandled = TRUE;
return 0;
}
}
}
}
}
我这种做法并不具备通用性。
void CControlUI::SetPos(RECT rc, bool bNeedInvalidate)
{
if( rc.right < rc.left ) rc.right = rc.left;
if( rc.bottom < rc.top ) rc.bottom = rc.top;
CDuiRect invalidateRc = m_rcItem;
if( ::IsRectEmpty(&invalidateRc) ) invalidateRc = rc;
if( m_bFloat ) {
CControlUI* pParent = GetParent();
/*if( pParent != NULL ) {
RECT rcParentPos = pParent->GetPos();
RECT rcCtrl = {rcParentPos.left + rc.left, rcParentPos.top + rc.top,
rcParentPos.left + rc.right, rcParentPos.top + rc.bottom};
m_rcItem = rcCtrl;
LONG width = rcParentPos.right - rcParentPos.left;
LONG height = rcParentPos.bottom - rcParentPos.top;
RECT rcPercent = {(LONG)(width*m_piFloatPercent.left), (LONG)(height*m_piFloatPercent.top),
(LONG)(width*m_piFloatPercent.right), (LONG)(height*m_piFloatPercent.bottom)};
m_cXY.cx = rc.left - rcPercent.left;
m_cXY.cy = rc.top - rcPercent.top;
m_cxyFixed.cx = rc.right - rcPercent.right - m_cXY.cx;
m_cxyFixed.cy = rc.bottom - rcPercent.bottom - m_cXY.cy;
}*/
}
else {
m_rcItem = rc;
}
m_rcItem = rc;
if( m_pManager == NULL ) return;
if( !m_bSetPos ) {
m_bSetPos = true;
if( OnSize ) OnSize(this);
m_bSetPos = false;
}
m_bUpdateNeeded = false;
if( bNeedInvalidate && IsVisible() ) {
invalidateRc.Join(m_rcItem);
CControlUI* pParent = this;
RECT rcTemp;
RECT rcParent;
while( pParent = pParent->GetParent() ) {
if( !pParent->IsVisible() ) return;
rcTemp = invalidateRc;
rcParent = pParent->GetPos();
if( !::IntersectRect(&invalidateRc, &rcTemp, &rcParent) ) return;
}
m_pManager->Invalidate(invalidateRc);
}
}
把一个控件设置为float后,再设置pos,只能放到父控件的左边位置,能不能设置pos为负值,放到父控件的右边
在支持多语言的情况下如果程序有弹出对话框,并且这个对话框继承自 WindowImplBase,当对对话框销毁后,主程序再一次弹出对话框或者含有菜单就会崩溃。
WindowImpBase::OnCreateTe()
{
......
// 多语言接口
CResourceManager::GetInstance()->SetTextQueryInterface(this); ///这个会被销毁
....
}
每次WindowImpBase集成的窗体每次销毁之后都需要重新设置m_pQuerypInterface
建议:
CResourceManager 不应该设置成单例
CDuiString CControlUI::GetText() const
{
if (!IsResourceText())
return m_sText;
//return CResourceManager::GetInstance()->GetText(m_sText);
return m_pManager->GetResouceManager()->GetText(m_sText)
}
上次的代码好像没有提交
老版本似乎没有这样的问题,当前版本很卡。
MainWnd.cpp(75): error C2065: “m_PaintManager”: 未声明的标识符
1>MainWnd.cpp(75): error C2228: “.FindControl”的左边必须有类/结构/联合
1> MainWnd.cpp(75): note: 类型是“unknown-type”
1>MainWnd.cpp(76): error C2065: “m_PaintManager”: 未声明的标识符
1>MainWnd.cpp(76): error C2228: “.FindControl”的左边必须有类/结构/联合
1> MainWnd.cpp(76): note: 类型是“unknown-type”
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.