当前位置: 首页 > 编程日记 > 正文

qt 拖拽 修改大小(二)

最近项目需要实现windows下橡皮筋的效果,所以对此做了一些了解,特此记录。

首先windows系统是支持橡皮筋效果的,需要使用win32方 法:SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, showFullWindow, NULL, 0);showFullWindow是一个变量,如果需要windows默认支持橡皮筋则需要传递参数false,否则传递参数true,如果使用 windows默认的橡皮筋缩放,效果如图1所示,会产生一个矩形框,不管是窗口移动还是放大缩小,都会对该矩形框作用,然后当鼠标弹起时,真实窗口才会 移动或者放大缩小。如果不使用橡皮筋拖拽的方式,那么窗口就是实时的拖拽。

图1 windows橡皮筋

在使用Qt窗口时,如果需要支持windows系统这种方式的拖拽,不能够使用setGeometry该函数来移动或者放大缩小窗口,而需要 重写QWidget::nativeEvent这个方法,该方法是在消息进入qt事件循环之前调用的,也就是说该方法会在mouseEvent等方法之前 调用,nativeEvent方法的实现请看另一篇文章qt 拖拽 修改大小,不过在我使用的过程中,使用了HTCAPTION这个属性后,原始窗口的双击放大事件被屏蔽掉了,到现在原因未搞清。在qt 拖拽 修改大小这篇文字中提到的bug,我用迂回的方式解决了,那就是使用Qt::WindowSystemMenuHint属性,但是窗口的放大和缩小使用另一种方式解决。

下面就是我使用代理的方式来支持窗口拖拽,由于该代理代码行数过多,我只写下重点的部分,该代理代码我也是从别人那儿拷贝的,后来根据我自己的理解和项目需求添加了一些东西。

代理头文件

  1 #ifndef NC_FRAMELESS_HELPER_H
  2 
  3 #define NC_FRAMELESS_HELPER_H
  4 
  5 #include
  6 
  7 #include
  8 
  9 #include
 10 
 11 #include "commonControls/include/commoncontrols_global.h"
 12 
 13 class WidgetResizeHandlerImpl;
 14 
 15 class CRubberBand : public QRubberBand
 16 
 17 {
 18 
 19 public:
 20 
 21     CRubberBand(QRubberBand::Shape s, QWidget * parent = nullptr);
 22 
 23     ~CRubberBand();
 24 
 25 protected:
 26 
 27     virtual void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
 28 
 29     virtual void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE;
 30 
 31     void changeEvent(QEvent *) Q_DECL_OVERRIDE;
 32 
 33     void showEvent(QShowEvent *) Q_DECL_OVERRIDE;
 34 
 35     void moveEvent(QMoveEvent *) Q_DECL_OVERRIDE;
 36 
 37 private:
 38 
 39 };
 40 
 41 //鼠标状态,可以获取鼠标当前和目标窗口的关系
 42 
 43 class CursorPosCalculator
 44 
 45 {
 46 
 47 public:
 48 
 49     CursorPosCalculator(){ reset(); }
 50 
 51     void reset();
 52 
 53     void recalculate(const QPoint& globalMousePos, const QRect& frameRect);
 54 
 55 public:
 56 
 57     bool onEdges;
 58 
 59     bool onLeftEdge;
 60 
 61     bool onRightEdge;
 62 
 63     bool onTopEdge;
 64 
 65     bool onBottomEdge;
 66 
 67     bool onTopLeftEdge;
 68 
 69     bool onBottomLeftEdge;
 70 
 71     bool onTopRightEdge;
 72 
 73     bool onBottomRightEdge;
 74 
 75     static int mBorderWidth;
 76 
 77 };
 78 
 79 //真正的处理操作类
 80 
 81 class WidgetData
 82 
 83 {
 84 
 85 public:
 86 
 87     WidgetData(WidgetResizeHandlerImpl * d, QWidget* topLevelWidget);
 88 
 89     ~WidgetData();
 90 
 91     QWidget * widget();
 92 
 93     void handleWidgetEvent(QEvent * event);//处理指定窗口事件入口函数
 94 
 95     void updateRubberBandStatus();
 96 
 97 private:
 98 
 99     void updateCursorShape(const QPoint& globalMousePos);
100 
101     void resizeWidget(const QPoint& globalMousePos);
102 
103     void moveWidget(const QPoint& globalMousePos);
104 
105     void handleMousePressEvent(QMouseEvent* event);
106 
107     void handleMouseReleaseEvent(QMouseEvent* event);
108 
109     void handleMouseMoveEvent(QMouseEvent* event);
110 
111     void handleLeaveEvent(QEvent* event);
112 
113     void handleHoverMoveEvent(QHoverEvent* event);
114 
115 private:
116 
117     bool mLeftButtonPressed = false;
118 
119     bool mCursorShapeChanged = false;
120 
121     Qt::WindowFlags mWindowFlags;
122 
123     QPoint mDragPos;//拖拽位置起点
124 
125     QWidget * mWidget = nullptr;//被代理的窗口指针
126 
127     CRubberBand * mRubberBand = nullptr;//橡胶类,支持橡胶操作
128 
129     CursorPosCalculator mPressedMousePos;//鼠标按下时光标信息
130 
131     CursorPosCalculator mMoveMousePos;//鼠标移动时光标信息
132 
133     WidgetResizeHandlerImpl * d_ptr;
134 
135 };
136 
137 ///说明:当QWidget设置了Qt::FramelessWindowHint属性时,可以借助该类完成:拖拽+窗口大小更改
138 
139 class COMMONCONTROLS_EXPORT WidgetResizeHandler : public QObject
140 
141 {
142 
143 public:
144 
145     explicit WidgetResizeHandler(QObject* parent = 0);
146 
147     ~WidgetResizeHandler();
148 
149 public:
150 
151     void activateOn(QWidget * topLevelWidget);//添加topLevelWidget事件代理
152 
153     void removeFrom(QWidget * topLevelWidget);//移除topLevelWidget事件代理
154 
155     Qt::CursorShape CursorShape(QWidget * widget);
156 
157     //窗口移动 default:true
158 
159     void setWidgetMovable(bool movable);
160 
161     bool isWidgetMovable();
162 
163     //大小可变 default:true
164 
165     void setWidgetResizable(bool resizable);
166 
167     bool isWidgetResizable();
168 
169     // 橡胶式窗口移动 default:false
170 
171     void useRubberBandOnMove(bool use);
172 
173     bool isUsingRubberBandOnMove();
174 
175     //橡胶式修改大小 default:false
176 
177     void useRubberBandOnResize(bool use);
178 
179     bool isUsingRubberBandOnResisze();
180 
181     void setBorderWidth(int newBorderWidth);
182 
183     int borderWidth();
184 
185     //局部可移动
186 
187     void useLocalMoveabled(bool use);
188 
189     void addLocalWidget(QWidget *);
190 
191 protected:
192 
193     virtual bool eventFilter(QObject * obj, QEvent * event) Q_DECL_OVERRIDE;//?????????????????????????????????????
194 
195 private:
196 
197     WidgetResizeHandlerImpl * d_ptr;
198 
199 };
200 
201 #endif // NC_FRAMELESS_HELPER_H
View Code
上边头文件中都有基本的注释,我就不过多解释了,下边我主要说下原理

在需要代理的类中声明WidgetResizeHandler对象,然后使用activateOn方法把需要代理的窗口添加到代理,注意被代 理的窗口需要含有Qt::Window属性明也就是需要时顶层窗口,如果对于一个复杂的窗口进行代理时,可能会出现一些意向不到的问题,比如:1、 QLabel接受富文本时,代理拿不到鼠标弹起事件,QToolButton对象不放到布局时,代理也拿不到鼠标弹起事件,这会导致代理不能正常使用,因 此我对该代理进行了修改,添加了useLocalMoveabled接口,允许代理只对局部窗口进行移动,这样是解决了我前边提到的两个问题。如果仔细看 应该也能看到我的代理也是使用setGeometry方法来拖拽窗口的,那么和我之前谈论的橡皮筋方式就有出入了,这个时候重点才来了,哈哈哈,继续往下 看,头文件中有个类CRubberBand,他是继承自QRubberBand,该类就模拟了一个橡皮筋的过程,只是qt提供的类接口有限,有一些写过很 难达到,比如说我要实现一些复杂的代理界面,那么我们就只能自己绘制了,我通过重新实现paintEvent函数,对该类画了一个灰色的矩形框,代码如 下:

QPainter p(this);

p.setPen(QPen(QColor(102, 102, 102), 4));

QRect rect = this->rect().adjusted(2, 2, -3, -3);

p.drawRect(rect);

如果照着我我上边所说的流程走,就会发现除了一个矩形框之外还会有一个背景色填充,这个时候就奇怪了,我们paintEvent并没有画背景 啊,呵呵呵,只需要在构造函数里加上这句话即可setAttribute(Qt::WA_NoSystemBackground),效果如图2所示。

图2 定制橡皮筋

下边我添加一些代理部分代码

1、CRubberBand构造函数

 1 CRubberBand::CRubberBand(QRubberBand::Shape s, QWidget * parent) :QRubberBand(QRubberBand::Rectangle, parent)
 2 
 3 {
 4 
 5     setAttribute(Qt::WA_TranslucentBackground);
 6 
 7 #ifndef Q_DEAD_CODE_FROM_QT4_WIN
 8 
 9     setAttribute(Qt::WA_NoSystemBackground);
10 
11 #endif //Q_DEAD_CODE_FROM_QT4_WIN
12 
13     setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
14 
15 }
View Code
2、使用activateOn后,窗口存储并验证
 1 WidgetData::WidgetData(WidgetResizeHandlerImpl * d, QWidget * topLevelWidget)
 2 
 3 {
 4 
 5     this->d_ptr = d;
 6 
 7     mWidget = topLevelWidget;
 8 
 9     mWidget->setMouseTracking(true);
10 
11     mWindowFlags = mWidget->windowFlags();
12 
13     //mWindowFlags |= Qt::CustomizeWindowHint | Qt::FramelessWindowHint;
14 
15     mWindowFlags |= Qt::FramelessWindowHint;
16 
17     mWidget->setWindowFlags(mWindowFlags);
18 
19     //mWidget->setWindowFlags( Qt::Popup | Qt::CustomizeWindowHint|Qt::FramelessWindowHint );
20 
21     //Bug fix, mouse move events does not propagate from child widgets.
22 
23     //so need the hover events.
24 
25     mWidget->setAttribute(Qt::WA_Hover);
26 
27     updateRubberBandStatus();
28 
29     bool visible = mWidget->isVisible();//防止非widget被代理
30 
31     mWidget->setVisible(visible);
32 
33 }
View Code
3、当被代理的窗口有鼠标事件时,先有代理处理
 1 void WidgetData::handleWidgetEvent(QEvent * event)
 2 
 3 {
 4 
 5     switch (event->type())
 6 
 7     {
 8 
 9     case QEvent::MouseButtonPress:
10 
11         handleMousePressEvent(static_cast(event));
12 
13         break;
14 
15     case QEvent::MouseButtonRelease:
16 
17         handleMouseReleaseEvent(static_cast(event));
18 
19         break;
20 
21     case QEvent::MouseMove:
22 
23         handleMouseMoveEvent(static_cast(event));
24 
25         break;
26 
27     case QEvent::Leave:
28 
29         handleLeaveEvent(event);
30 
31         break;
32 
33     case QEvent::HoverMove:
34 
35         handleHoverMoveEvent(static_cast(event));
36 
37         break;
38 
39     }
40 
41 }
View Code
4、下边5个函数分别是上边的具体实现
  1 void WidgetData::handleMousePressEvent(QMouseEvent * event)
  2 
  3 {
  4 
  5     if (event->button() == Qt::LeftButton)
  6 
  7     {
  8 
  9         mLeftButtonPressed = true;
 10 
 11         QRect frameRect = mWidget->frameGeometry();
 12 
 13         mPressedMousePos.recalculate(event->globalPos(), frameRect);
 14 
 15         mDragPos = event->globalPos() - frameRect.topLeft();
 16 
 17         if (mPressedMousePos.onEdges)
 18 
 19         {
 20 
 21             if (d_ptr->mUseRubberBandOnResize)
 22 
 23             {
 24 
 25                 mRubberBand->setGeometry(frameRect);
 26 
 27                 //mRubberBand->show();
 28 
 29             }
 30 
 31         }
 32 
 33         else if (d_ptr->mUseRubberBandOnMove)
 34 
 35         {
 36 
 37             mRubberBand->setGeometry(frameRect);
 38 
 39             //mRubberBand->show();
 40 
 41         }
 42 
 43         if (d_ptr->mLocalOnMove)//启用局部拖拽功能后   需要处理不在指定范围内的拖拽,并过滤掉
 44 
 45         {
 46 
 47             bool canMove = false;
 48 
 49             for (int i = 0; i < d_ptr->mLocalWidget.size(); ++i)
 50 
 51             {
 52 
 53                 if (d_ptr->mLocalWidget[i]->rect().contains(d_ptr->mLocalWidget[i]->mapFromGlobal(event->globalPos())))
 54 
 55                 {
 56 
 57                     canMove = true;
 58 
 59                     break;
 60 
 61                 }
 62 
 63             }
 64 
 65             if (canMove == false && mPressedMousePos.onEdges == false)
 66 
 67             {
 68 
 69                 mLeftButtonPressed = false;
 70 
 71             }
 72 
 73         }
 74 
 75     }
 76 
 77 }
 78 
 79 void WidgetData::handleMouseReleaseEvent(QMouseEvent* event)
 80 
 81 {
 82 
 83     if (event->button() == Qt::LeftButton)
 84 
 85     {
 86 
 87         d_ptr->mCanMoveFlag = false;
 88 
 89         mLeftButtonPressed = false;
 90 
 91         mPressedMousePos.reset();
 92 
 93         if (mRubberBand && mRubberBand->isVisible())
 94 
 95         {
 96 
 97             mRubberBand->hide();
 98 
 99             mWidget->setGeometry(mRubberBand->geometry());
100 
101         }
102 
103     }
104 
105 }
106 
107 void WidgetData::handleMouseMoveEvent(QMouseEvent* event)
108 
109 {
110 
111     if (mLeftButtonPressed)
112 
113     {
114 
115         if (d_ptr->mWidgetResizable && mPressedMousePos.onEdges)
116 
117         {
118 
119             resizeWidget(event->globalPos());
120 
121         }
122 
123         else if (d_ptr->mWidgetMovable)
124 
125         {
126 
127             moveWidget(event->globalPos());
128 
129         }
130 
131     }
132 
133     else if (d_ptr->mWidgetResizable)
134 
135     {
136 
137         updateCursorShape(event->globalPos());
138 
139     }
140 
141 }
142 
143 void WidgetData::handleLeaveEvent(QEvent*)
144 
145 {
146 
147     if (!mLeftButtonPressed)
148 
149     {
150 
151         mWidget->unsetCursor();
152 
153     }
154 
155 }
156 
157 void WidgetData::handleHoverMoveEvent(QHoverEvent* event)
158 
159 {
160 
161     if (mLeftButtonPressed)
162 
163     {
164 
165         return;
166 
167     }
168 
169     if (d_ptr->mWidgetResizable)
170 
171     {
172 
173         updateCursorShape(mWidget->mapToGlobal(event->pos()));
174 
175     }
176 
177 }
View Code

5、更新鼠标状态

 1 void WidgetData::updateCursorShape(const QPoint & globalMousePos)
 2 
 3 {
 4 
 5     if (mWidget->isFullScreen() || mWidget->isMaximized())
 6 
 7     {
 8 
 9         if (mCursorShapeChanged)
10 
11         {
12 
13             mWidget->unsetCursor();
14 
15         }
16 
17         return;
18 
19     }
20 
21     mMoveMousePos.recalculate(globalMousePos, mWidget->frameGeometry());
22 
23     if (mMoveMousePos.onTopLeftEdge || mMoveMousePos.onBottomRightEdge)
24 
25     {
26 
27         mWidget->setCursor(Qt::SizeFDiagCursor);
28 
29         mCursorShapeChanged = true;
30 
31     }
32 
33     else if (mMoveMousePos.onTopRightEdge || mMoveMousePos.onBottomLeftEdge)
34 
35     {
36 
37         mWidget->setCursor(Qt::SizeBDiagCursor);
38 
39         mCursorShapeChanged = true;
40 
41     }
42 
43     else if (mMoveMousePos.onLeftEdge || mMoveMousePos.onRightEdge)
44 
45     {
46 
47         mWidget->setCursor(Qt::SizeHorCursor);
48 
49         mCursorShapeChanged = true;
50 
51     }
52 
53     else if (mMoveMousePos.onTopEdge || mMoveMousePos.onBottomEdge)
54 
55     {
56 
57         mWidget->setCursor(Qt::SizeVerCursor);
58 
59         mCursorShapeChanged = true;
60 
61     }
62 
63     else
64 
65     {
66 
67         if (mCursorShapeChanged)//修改鼠标状态
68 
69         {
70 
71             mWidget->unsetCursor();
72 
73             mCursorShapeChanged = false;
74 
75         }
76 
77     }
78 
79 }
View Code
6、修改窗口大小和移动位置
  1 void WidgetData::resizeWidget(const QPoint& globalMousePos)
  2 
  3 {
  4 
  5     QRect origRect;
  6 
  7     if (d_ptr->mUseRubberBandOnResize)
  8 
  9     {
 10 
 11         origRect = mRubberBand->frameGeometry();
 12 
 13     }
 14 
 15     else
 16 
 17     {
 18 
 19         origRect = mWidget->frameGeometry();
 20 
 21     }
 22 
 23     int left = origRect.left();
 24 
 25     int top = origRect.top();
 26 
 27     int right = origRect.right();
 28 
 29     int bottom = origRect.bottom();
 30 
 31     origRect.getCoords(&left, &top, &right, &bottom);
 32 
 33     int minWidth = mWidget->minimumWidth();
 34 
 35     int minHeight = mWidget->minimumHeight();
 36 
 37     if (mPressedMousePos.onTopLeftEdge)
 38 
 39     {
 40 
 41         left = globalMousePos.x();
 42 
 43         top = globalMousePos.y();
 44 
 45     }
 46 
 47     else if (mPressedMousePos.onBottomLeftEdge)
 48 
 49     {
 50 
 51         left = globalMousePos.x();
 52 
 53         bottom = globalMousePos.y();
 54 
 55     }
 56 
 57     else if (mPressedMousePos.onTopRightEdge)
 58 
 59     {
 60 
 61         right = globalMousePos.x();
 62 
 63         top = globalMousePos.y();
 64 
 65     }
 66 
 67     else if (mPressedMousePos.onBottomRightEdge)
 68 
 69     {
 70 
 71         right = globalMousePos.x();
 72 
 73         bottom = globalMousePos.y();
 74 
 75     }
 76 
 77     else if (mPressedMousePos.onLeftEdge)
 78 
 79     {
 80 
 81         left = globalMousePos.x();
 82 
 83         int max_width = mWidget->maximumWidth();
 84 
 85         if (right - left > max_width)
 86 
 87         {
 88 
 89             return;
 90 
 91         }
 92 
 93     }
 94 
 95     else if (mPressedMousePos.onRightEdge)
 96 
 97     {
 98 
 99         right = globalMousePos.x();
100 
101     }
102 
103     else if (mPressedMousePos.onTopEdge)
104 
105     {
106 
107         top = globalMousePos.y();
108 
109     }
110 
111     else if (mPressedMousePos.onBottomEdge)
112 
113     {
114 
115         bottom = globalMousePos.y();
116 
117     }
118 
119     QRect newRect(QPoint(left, top), QPoint(right, bottom));
120 
121     if (newRect.isValid())
122 
123     {
124 
125         if (minWidth > newRect.width())
126 
127         {
128 
129             //determine what has caused the width change.
130 
131             if (left != origRect.left())
132 
133                 newRect.setLeft(origRect.left());
134 
135             else
136 
137                 newRect.setRight(origRect.right());
138 
139         }
140 
141         if (minHeight > newRect.height())
142 
143         {
144 
145             //determine what has caused the height change.
146 
147             if (top != origRect.top())
148 
149                 newRect.setTop(origRect.top());
150 
151             else
152 
153                 newRect.setBottom(origRect.bottom());
154 
155         }
156 
157         if (d_ptr->mUseRubberBandOnResize)
158 
159         {
160 
161             if (mRubberBand->isVisible() == false)
162 
163             {
164 
165                 mRubberBand->show();
166 
167             }
168 
169             mRubberBand->setGeometry(newRect);
170 
171         }
172 
173         else
174 
175         {
176 
177             //mWidget->setGeometry(newRect);
178 
179             mWidget->move(newRect.topLeft());
180 
181             mWidget->resize(newRect.size());
182 
183         }
184 
185     }
186 
187     else
188 
189     {
190 
191         //qDebug() << "Calculated Rect is not valid" << newRect;
192 
193     }
194 
195 }
196 
197 void WidgetData::moveWidget(const QPoint & globalMousePos)
198 
199 {
200 
201     bool canMove = false;
202 
203     if (d_ptr->mLocalOnMove == true && d_ptr->mCanMoveFlag != true)
204 
205     {
206 
207         for (int i = 0; i < d_ptr->mLocalWidget.size(); ++i)
208 
209         {
210 
211             if (d_ptr->mLocalWidget[i]->rect().contains(d_ptr->mLocalWidget[i]->mapFromGlobal(globalMousePos)))
212 
213             {
214 
215                 canMove = true;
216 
217                 d_ptr->mCanMoveFlag = true;
218 
219                 break;
220 
221             }
222 
223         }
224 
225     }
226 
227     else
228 
229     {
230 
231         canMove = true;
232 
233     }
234 
235     if (canMove)
236 
237     {
238 
239         if (d_ptr->mUseRubberBandOnMove)
240 
241         {
242 
243             if (mRubberBand->isVisible() == false)
244 
245             {
246 
247                 mRubberBand->show();
248 
249             }
250 
251             mRubberBand->move(globalMousePos - mDragPos);
252 
253         }
254 
255         else
256 
257         {
258 
259             mWidget->move(globalMousePos - mDragPos);
260 
261         }
262 
263     }
264 
265 }
View Code

相关文章:

互联网大厂技术面试内幕@霞落满天

很多求职者往往并非因为技术不好&#xff0c;而是没有掌握面试的技巧导致不能把握机会&#xff0c;本课程的目的就是本课程先通过比较真实的好简历和不好的简历让大家明白自己的简历有哪些问题&#xff0c;事实上简历是大厂的敲门砖&#xff0c;非常重要&#xff0c;很多人得不…

【数据结构】顺序表的应用(1)(C语言)

问题&#xff1a; 1.将顺序表(a1,a2,…,an)重新排列以a1为界的两部分&#xff1a;a1前面的值均比a1小&#xff0c;a1后面的值均比a1大&#xff08;这里假设数据元素的类型具有可比性&#xff0c;不妨设为整型&#xff09;。 头文件与该头文件一样&#xff1a;【数据结构】顺序…

比特币寒冬中,你更应该关注企业区块链!

公众对区块链的认识也许限于比特币或以太坊&#xff0c;但很多却不知道 Hyperledger&#xff08;超级账本&#xff09;。Hyperledger Fabric&#xff0c;是由 IBM 带头发起的一个联盟链项目&#xff0c;2015 年末移交给 Linux 基金会&#xff0c;成为开源项目。Linux 基金会孵化…

JVM XMX设置多大比较好,Docke容器里该怎么设置JVM呢@无界编程

XMX是JVM的最大堆内存大小,XMS是JVM的初始堆内存大小。 不管是工作还是面试经常遇到一个问题就是XMX到底设置多大比较好? 网上的答案大多是说XMX和XMS设置为一样大,但是没有说到底XMX设置多大比较好。 如果设置为和操作系统一样大内存会怎么样? 这篇文章就带你搞清楚这…

【数据结构】顺序表的应用(2)(C语言)

问题&#xff1a; 2.有顺序表A和B&#xff0c;其元素均按从小到大的升序排列&#xff0c;编写一个算法&#xff0c;将它们合并成一个顺序表C&#xff0c;要求C的元素也按从小到大的升序排列。 头文件与该头文件一样&#xff1a;【数据结构】顺序表的实现&#xff08;C语言&am…

OWA登录页面显示为英文而不是中文

-----提供AD\Exchange\Lync\Sharepoint\CRM\SC\O365等微软产品实施及外包&#xff0c;QQ:185426445.电话18666943750故障描述&#xff1a;WIN10操作系统使用IE登录OWA的时候&#xff0c;界面语言为英文&#xff0c;WIN10操作系统为中文系统&#xff0c;区域语言都是设置为中文&…

java B2B2C springmvc mybatis多租户电子商城系统-Spring Cloud Feign

1、什么是Feign&#xff1f; 愿意了解源码的朋友直接企鹅求求&#xff1a;二一四七七七五六三三 Feign 的英文表意为“假装&#xff0c;伪装&#xff0c;变形”&#xff0c; 是一个http请求调用的轻量级框架&#xff0c;可以以Java接口注解的方式调用Http请求&#xff0c;而不用…

【数据结构】顺序表的应用(3)(C语言)

问题&#xff1a; 已知一个顺序表中的各节点值是从大到小有序的&#xff0c;设计一个算法&#xff0c;插入一个值为x的节点&#xff0c;使顺序表中的节点仍然是从小到大有序的。 头文件与该头文件一样&#xff1a;【数据结构】顺序表的实现&#xff08;C语言&#xff09; #i…

从源码和内核角度分析redis和nginx以及java NIO可以支持多大的并发

有人询问我网上一篇关于“redis为什么单线程这么快”的文章,我建议他不要看了,因为redis是单进程不是单线程,后面的意见不用看了,文章质量肯定不会很好,他也说了自己看了很久源码似乎还是有些云里雾里,所以我就给他分析了为什么redis这么快,这篇主要讲epoll的实现。 从…

背景图片等比缩放的写法background-size简写法

1、背景图片或图标也可像img一样给其宽高就能指定其缩放大小了。 比如一个实际宽高36*28的图标&#xff0c;要缩小一半引用进来的写法就是&#xff1a; background:rgba(0, 0, 0, 0) url("../images/report_icon2x.png") no-repeat scroll left center / 18px 14px; …

深入了解以太坊

正在看这篇文章的你&#xff0c;应该是一名被区块链技术所吸引的开发者或者极客。我相信你已经理解了区块链的技术原理&#xff0c;并急切地想要搞清楚这项技术将为你和你的开发技术栈带来怎样的影响。 如果你需要更基础的区块链技术介绍&#xff0c;可以阅读比特币和以太坊的白…

Netty和JDK源码来看Netty的NIO和JDK的NIO有什么不同

JDK底层提供了NIO实现,在Linux环境会调用内核epoll。 但是Netty通过JNI的方式提供了Native Socket Transport,为什么Netty要自己搞一套NIO呢? 这篇文章带你从jdk的源码和Netty的源码角度来分析为什么Netty要这么做。 JDK源码:openjdk-8u40 Netty源码:netty-4.1 1.先看J…

【数据结构】单链表的实现(C语言)

单链表是线性表链式储存的一种形式&#xff0c;其中的结点一般含有两个域&#xff0c;一个是存放数据信息的info域&#xff0c;另一个是指向该结点后继结点存放地址的指针next域。一个单链表必须要有一个首指针指向链表中的第一个结点。 单链表要掌握以下几种操作&#xff1a;…

《理解 OpenStack + Ceph》---来自-[爱.知识]-推荐

企业IT技术分享&#xff08;2016-06-29&#xff09;来自&#xff08;QQ群&#xff1a;企业私有云平台实战 454544014-推荐&#xff09;&#xff01;理解 OpenStack Ceph &#xff08;1&#xff09;&#xff1a;Ceph OpenStack 集群部署和配置http://www.cnblogs.com/sammyliu…

windows10 安装 mysql8.0.12 详解

【1】下载安装包 官网下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 如下图所示&#xff1a; 下载完成&#xff0c;安装包为mysql-8.0.12-winx64.zip 【2】安装准备 &#xff08;1&#xff09;安装路径。拷贝安装包到任意路径&#xff0c;然后解压缩。…

IDEA常用和实用配置以及各种必要插件

主要是收集IDEA常用和不常用配置陆续更新 ------------------------ 启动项目配置 建议使用idea2021.1.3以上版本&#xff1a; ------------------------ maven没有设置自动导包&#xff0c;导致引用不到第三方依赖。 可以点maven的刷新按钮即可。 idea 设置gradle自动更…

linux 调试利器gdb, strace, pstack, pstree, lsof

1)如何使用stracepstack利器分析程序性能?http://www.cnblogs.com/bangerlee/archive/2012/04/30/2476190.html此文有详细介绍怎么用strace和pstack2)Linux下多线程查看工具(pstree、ps、pstack)?http://blog.csdn.net/yfkiss/article/details/67293643)使用strace,lstrace,t…

【数据结构】单链表的应用(C语言)

1、设计一个算法&#xff0c;求一个单链表中的节点数 2、设计一个算法&#xff0c;在一个单链表中值为y的结点前插入一个值为x的结点&#xff08;值为x的新结点为成为值为y的结点前驱结点&#xff09; 3、设计一个算法&#xff0c;判断单链表中各结点是否有序 4、设计一个算…

物联网设备僵尸网络趋势分析

物联网&#xff08;IoT&#xff09;僵尸网络作者正在适应更安全的物联网设备的转变&#xff0c;这已经将***者的注意力转移到利用物联网设备的漏洞上。由于物联网设备安全性仍处于起步阶段&#xff0c;因此发现命令注入等基本漏洞并不少见。2018年11月&#xff0c;NetScout的As…

Redis6安装配置集群cluster以及集群宕机注意事项

Redis6的cluster模型推荐3主3从 先准备3台服务器&#xff0c;每个上面部署2个redis&#xff0c;服务器配置2核2G&#xff1a; 下面在每台服务器安装redis6&#xff0c;每台机器只要安装一次即可&#xff0c;然后分别配置2个端口的conf文件&#xff0c;分别起来即可&#xff1a…

【数据结构】循环单链表的实现(C语言)

循环单链表应掌握以下基本操作&#xff1a; 1、建立一个空的循环单链表。 2、获得循环单链表的最后一个结点的位置。 3、输出循环单链表中各结点的值。 4、在循环单链表中查找值为x的结点。 5、在循环单链表中第i个结点后插入值为x的新结点。 6、在循环单链表中删除值为x…

DTRACE 专家

http://dtrace.org/blogs/bmc/ https://github.com/bcantrill http://www.tudou.com/programs/view/Q6fHZFgZww4 http://dtrace.org/blogs/ahl/2012/04/24/btrace-dtrace-for-java-ish/ JAVA https://github.com/chrisa https://github.com/ahrens

统一客服消息返回错误:{errcode:43004,errmsg:require subscribe hint: [9Vv08633952]}

2019独角兽企业重金招聘Python工程师标准>>> 公众号或者小程序发送客服消息错误&#xff1a; {"errcode":43004,"errmsg":"require subscribe hint: [9Vv08633952]"} 场景&#xff1a;小程序使用公众号的服务消息&#xff0c;推送消息…

sublime Text 开发工具

简介描述 Sublime Text 是一个跨平台的编辑器&#xff0c;同时支持Windows、Linux、Mac OS X等操作系统。,具有漂亮的用户界面和强大的功能&#xff0c;例如代码缩略图&#xff0c;Python的插件&#xff0c;代码段等。还可自定义键绑定&#xff0c;菜单和工具栏。Sublime Text …

【数据结构】双链表的实现(C语言)

双链表中的结点包括3个域&#xff0c;一个是存放数据信息的info域&#xff0c;另两个是指阵域&#xff0c;这里用llink和rlink表示&#xff0c;llink指向它的前驱结点&#xff0c;rlink指向它的后继结点。 双链表要掌握以下基本操作&#xff1a; 1、创建一个空的双链表。 2、…

ShardingSphere-Proxy分库分表以及多租户安装使用

需求&#xff1a;你提供SAAS服务&#xff0c;你有你有2个租户(商户)&#xff0c;各自的数据进各自的库&#xff0c;而你不希望你的微服务java里默认配置多个租户数据源&#xff0c;数据连接池太多&#xff0c;而且后面动态增加也不方便&#xff0c;诸如此类很多问题。 方案&am…

jenkins自动化部署工具

jenkins自动化测试 & 持续集成 知识点&#xff1a; 1。下载地址&#xff1a;jenkins.io download: 转载于:https://www.cnblogs.com/kaixinyufeng/p/10123419.html

android 图片水印处理 文字倾斜处理

方法一&#xff1a; 获取一个textview 从textview中获取bitmap&#xff0c;将bitmap 通过matrix进行角度变换&#xff0c;然后将原图和此bitmap合并&#xff1b; 方法二&#xff1a; 将原图获取bitmap后&#xff0c;得到canvas&#xff0c;将canvas进行角度变换&#xff0c;…

Centos下MySQL安装与配置

一、mysql简介说到数据库&#xff0c;我们大多想到的是关系型数据库&#xff0c;比如mysql、oracle、sqlserver等等&#xff0c;这些数据库软件在windows上安装都非常的方便&#xff0c;在Linux上如果要安装数据库&#xff0c;咱不得不首先推荐的是mysql数据库了&#xff0c;而…

【数据结构】链式栈的实现(C语言)

栈的链式存储称为链式栈&#xff0c;链式栈是一种特殊的单链表&#xff0c;它的插入和删除规定在单链表的同一端进行。链式栈的栈顶指针一般用top表示。&#xff08;个人理解&#xff1a;相当于只对单链表的第一个结点进行操作&#xff09; 链式栈要掌握以下基本操作&#xff1…