精华内容
下载资源
问答
  • 纯css控制文字2行显示多余部分隐藏

    万次阅读 2016-07-01 10:24:34
    在编写页面的时候,经常遇到一些地方的文字显示1行,多余的文字隐藏,这样显示1行的很好控制: css代码如下: white-space: nowrap; overflow: hidden; text-overflow: ellipsis; 3行代码搞定,这个很常见。...

    在编写页面的时候,经常遇到一些地方的文字显示1行,多余的文字隐藏,这样显示1行的很好控制:

    css代码如下:

    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    3行代码搞定,这个很常见。但是要是2行文字显示多余隐藏呢,我之前在网上搜到的很多说什么用js去控制,用php控制。。。等等诸如此类的复杂方法,为什么不能同样用css去控制呢?后来找到答案了,用css同样可以去控制2行文字显示多余隐藏。

    css代码如下:

    text-overflow: -o-ellipsis-lastline;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    更方便的是改变webkit-line-clamp的值还可以实现3、4、5等等多行文字显示多余隐藏的效果~






    展开全文
  • div内图片和文字水平垂直居中

    万次阅读 2017-11-29 17:32:36
    大小不固定的图片、多行文字的水平垂直居中 本文综述 想必写css的都知道如何让单行文字在高度固定的容器内垂直居中,但是您知道或者想过让行数不固定的文字在高度固定的容器内垂直居中呢?本文将会告诉你如何实现...

     

    大小不固定的图片、多行文字的水平垂直居中

     

    本文综述

    想必写css的都知道如何让单行文字在高度固定的容器内垂直居中,但是您知道或者想过让行数不固定的文字在高度固定的容器内垂直居中呢?本文将会告诉你如何实现多行文字的垂直居中显示。
    关于图片垂直居中显示,想必很多写css的人都研究过,或者说是搜寻过方法。淘宝团队似乎提供了一种不错的方法,用font-size解决IE下垂直居中的问题,是个好方法吗?是的,方法是不错,可是问题也很多:不支持img外标签的浮动,致使多图片排列时需添加额外标签;需要记住一些比例参数,上手较难;原理艰深,兼容性不稳定等。但是在我看来,这个方法不足够好!本文将提供两种更为新颖的方法,代码简洁,原理简单,上手容易,兼容性强,出错率低的方法。inline-block裸标签对齐法,以及透明图片拉伸对齐法
    css是如此的精深,相信后来人会有更加绝妙的方法。但是,本文提供的几种实现图片垂直居中方法,一定是目前最实用的几种方法。

    一、大小不固定,多行文字的垂直居中

    ① 单行文字
    可能很多人都知道如何让单行文字垂直居中显示,就是使用line-height,将line-height值与外部标签盒子的高度值设置成一致就可以了。例如如下css代码:height:3em; line-height:3em; ……
    显示结果如下图:

    单行文本垂直居中对齐-鑫空间-鑫生活

    单行文本垂直居中对齐-鑫空间-鑫生活

    ② 多行文字
    如何实现父容器高度固定,文字可能一行,两行或更多行的垂直居中对齐呢?
    实现的关键是把文字当图片处理。用一个span标签将所有的文字封装起来,设置文字与图片相同的display属性(inline-block属性),然后用处理图片垂直居中的方式处理文字的垂直居中即可。
    核心css代码如下,
    外部div标签:

    div{display:table-cell; width:550px; height:1.14em; padding:0 0.1em; border:4px solid #beceeb; color:#069; font-size:10em; vertical-align:middle;}

    内部span标签:

    span{display:inline-block; font-size:0.1em; vertical-align:middle;}

    下面这张是实例演示页面的效果截图:

    行数不固定文字垂直居中对齐

    行数不固定文字垂直居中对齐

    有几点简要说明:
    1.此例子用em做单位,如果您对em单位了解不够,把握不来的话,可以使用px做单位,值要换;
    2.外部div不能使用浮动;
    3.外部div高度和文字大小比例1.14为宜;
    4.内部标签的vertical-align:middle可以省略,但是外部div高度和文字大小比例要修改,我自己试了一下,高度比字体1.5左右的样子;
    5.系统原因,我没能够在IE8下测试。

    实现的最终效果和JavaScript演示,您可以狠狠地点击这里去看看。

    二、大小不固定,图片的水平垂直居中

    ① 透明gif图片+背景定位的方法
    这里利用了background-position:center实现图片居中显示。这是个很实用也是很聪明的办法,对于维护控制成本都很不错。微软必应图片搜索的图片排列就是使用的这种方法。
    方法的原理很简单,使用一个透明的gif图片做覆盖层,高宽拉伸至所需要的大小,然后给这个gif图片一个background- position:center center的属性。而background-image建议写在页面上,因为实际项目中,这肯定是个动态的URL地址,css文件似乎不支持动态URL 地址。下面就是实例演示页面的效果截图。

    透明图片和背景定位实现图片水平垂直居中

    透明图片和背景定位实现图片水平垂直居中

    核心HTML代码为:

    <img src="../image/pixel.gif" style="background-image:url(http://image.zhangxinxu.com/image/study/s/s128/mm1.jpg);" />

    其中此img标签已经设置了高宽和背景居中定位的属性。具体实现可以可以狠狠地点击这里进行参照。

    ② display:table-cell和文字大小控制居中

    这个方法可以说就是本文综述部分提到的淘宝团队想出的图片垂直居中的方法。但是本文展示的这个方法的css代码又不是淘宝工程师们的原版代码,我对其做了一定的修改,把里面没有用可以剔除的hack都去掉了。

    css代码部分:
    img外部div标签:

    div {display:table-cell; width:1em; height:1em; font-size:144px; width:144px; height:144px; font-size:118px; border:1px solid #beceeb; text-align:center; vertical-align:middle;}/*这里的大小是根据高宽上限128像素图片设置的*/

    img标签:

    img{vertical-align:middle;}

    需要说明的:
    1.原版的代码中有两个hack,一个是针对文字大小的,另外一个是针对block属性的;后经过我测试推敲后证实这两个hack都是多余的,而*display:block更是多余,因为IE6,IE7根本就不认识display:table-cell是谁!
    2.这个通过文字大小控制IE下图片垂直居中是个很不错的方法,要比使用position:relative这类高消耗的css方法要好多了。但是这个方法不足之处在于:不支持img外标签的浮动,所以当多图片显示时需要再在外面嵌套一层标签——资源消耗多了!
    3.高度:文字大小=1.14,这个比例我一直记着,但是后来我将这个比例的概念淡化了,原因在于多次遇到其他比例实现效果的情况。例如上面,就是1:1实现的。

    这里附上效果截图(取自IE6浏览器):

    table-cell和文字大小实现的图片垂直居中显示

    table-cell和文字大小实现的图片垂直居中显示

    图片和文字比不上直接的效果显示,所以建议您狠狠地点击这里

    ③ display:inline-block和文字大小控制居中
    此方法的灵感来自于Google picasa相册的图片显示,代码相当简洁,是个成本很低,效果惊人的方法。适用于多图显示的情况。基本上用裸标签就实现了想要达到的效果。一般而言,图片阵列排列显示的时候,外面都有一个a标签的,起到链接的作用。而本处的方法就只要这一个a标签就足以实现图片垂直且居中的显示效果。其关键是将a标签默认的inline属性设置为inline-block属性,这样a标签既支持宽度,又支持vertical-align:middle,配合img的vertical-align:middle就可以实现图片的水平垂直居中显示了。
    css代码:
    a标签:

    a{display:inline-block; width:1.2em; font-size:128px; text-align:center; vertical-align:middle;}

    img标签:

    img{vertical-align:middle;}

    就这么简单,就实现了图片的垂直居中效果。下截图为证:

    最精简的实现图片水平垂直居中显示的方法

    最精简的实现图片水平垂直居中显示的方法

    另外补充说明的:img外的标签需是a标签或span这类inline属性的标签,div标签也可以,但是css代码多些: display:inline-block;*display:inline; zoom:1; IE下要先变成inline属性,再转变成类似于inline-block的属性,原因讲起来又是一篇长长的文章,放着。

    建议您狠狠地点击这里直接查看源代码

    ④ 透明图片拉伸对齐实现垂直居中显示
    这个方法是自认为相当不错的一个方法,说实话,想到这个方法是自然而然的,经过试验发现真的很管用。对比淘宝团队的方法,发现优势很多,基本上淘宝的table-cell+font-size方法会带来的些问题都避免了。
    非常简单,非常易懂,出错率低,上手方便,兼容性上佳!

    原理简述:
    一句话,将要显示的图片与一张透明的高度100%,宽度1像素的透明图片vertical-align:middle对齐。
    其核心原理其实与利用font-size大小实现IE下图片垂直居中是一致的。将font-size设置得很大,目的是撑开IE下默认文字空间的高度,其性质类似于空格,然后通过vertical-align:middle属性让图片与这个高高的空白空格空间垂直居中对齐;而这里将这个看不见的文字空间实例成一张透明的gif图片,高度可以轻松设置为外部标签的高度,宽度压缩至最小,然后通过vertical-align:middle对齐,就实现效果了,由于影响布局的差不多就vertical-align:middle这一个属性,所以出现兼容性问题的可能性比table-cell的方法要低得多。
    需要注意的:
    1.img外容器宽度要大于要显示的图片的最大宽度+1像素;
    2.img外容器的字体大小设为0px,也可以不设,但是两个img标签要连着写,避免空格;

    以下是核心的一些代码:
    HTML部分:

    <li>
        <img data-src="http://image.zhangxinxu.com/image/study/s/s128/mm1.jpg" /><img src="../image/pixel.gif" />
    </li>

    css部分:

    li{height:128px; width:150px; padding:13px 0; float:left; margin-right:10px; border:1px solid #beceeb; text-align:center; font-size:0;}
    li .alpha_img{height:100%; width:1px; vertical-align:middle;}
    li .alpha_img{height:100%; width:0; vertical-align:middle;}
    li .show_img{vertical-align:middle;}
    

    其实,只要有上面绿色部分的css代码就足够了。
    简单的超乎想象。

    要显示的图片后面跟了一个高度撑满容器,只有1px宽,宽度为0即可,透明的图片。这两个图片分别vertical-align:middle,就实现了要显示的图片与这个拉伸的透明图片的居中对齐了,由于透明图片是透明的,不可见的,宽度也只有1像素宽度也为0,所以看上去就是要显示的图片相对于容器垂直居中了。

    另外,其实这里不一定是透明的图片,使用任意的图片都可以,所以您其实说不定可以减少一次http请求,使用任意的图片将其拉伸至高度为容器高,宽度1像素宽度0就可以了。

    甚至,使用span标签,div标签也可以实现同样的效果。只要将span标签或div标签转换成inline-block属性或类似于inline-block属性就可以了。
    我个人更推荐使用行内元素,例如span,i标签等,只要应用类似下面的CSS:

    span{display:inline-block; height:100%; width:0; vertical-align:middle;}

    相比图片而言,多了个display:inline-block; 但是会少一次链接请求。效果图和上面的一样的,完美的水平垂直居中。原理也与图片一样,相信很容易理解的。

    再提供一下实例页面的链接,狠狠地点击这里,实例页面的最后一种方法向您展示了这种新颖的图片垂直居中的方法。

    最后,说句实在话,我知道这应该不算什么新颖的方法,在我之前想到这种方法的人肯定不在少数,但是留迹于网上的却没有,我是没有发现过。我不清楚是这些大牛的公司要求技术保密,还是自身不愿分享研究成果。我相信不是这样的,主要还是他们很忙碌,没有时间写这些东西。像我这样,”闲暇”的很,花十几个小时写一篇文章的估计不多,呵呵。

    补充于2009-11-03 15:32
    正如我经常挂在嘴边的,css博大精深,你需要花费精力去观察它,研究它。这里,我再提供一种我刚刚试验出来的一种新方法,实现大小不固定的图片水平垂直居中,综合来讲,比上面所有提供的方法还要优秀,且没有hack,兼容性上佳(支持IE6、IE7、Firefox、chrome、Safari浏览器-IE8未测(补充:我后来又测试了一下,结果在IE8浏览器和Opera浏览器下是不垂直居中的,所有此方法还是有待商榷的)。下为在IE7下的效果截图:
    新方法实现图片垂直居中
    此方法原理是,在IE下使用font-size使图片垂直居中显示,Firefox,chrome等现代浏览器使用line-height配合img本身的vertical-align属性使垂直居中显示,由于两者不冲突,所以没有hack就实现的效果。css代码简洁明了,关键是HTML代码非常清晰,一层外标签,里面就是img标签,我想很难再找出比这个方法更出色的让图片水平垂直居中的方法了。好吧,其实这个方法是有一点不完美的,就是opera浏览器下图片无法垂直居中显示,幸好国内而言,使用opera浏览器的比例很低,所以综合来讲这个方法是个非常优秀的图片水平垂直居中的方法。

    以下为css代码部分:

    .zxx_ul_image li{float:left; width:150px; height:150px; text-align:center; line-height:150px; font-size:125px;}
    .zxx_ul_image li img{vertical-align:middle;}
    
    .zxx_ul_image li{float:left; width:150px; height:150px; text-align:center; line-height:150px; *font-size:125px;}
    .zxx_ul_image li:after{content:' '; vertical-align:middle;}
    .zxx_ul_image li img{vertical-align:middle;}
    展开全文
  • 文字不能超过三行,多余使用…,但是保持价格可见。实现功能一:图片与文字中间对齐看到设计图就想到使用TextView.drawableLeft属性,加上Html,发现图片居中于全部文字,而不是居中与第一行文字。后面采用Html.src...

    Android使用ImageSpan,图片不能与文字对齐问题

    实现如下产品需求
    - 1. 图片与文字中间对齐
    - 2. 文字不能超过三行,多余使用…,但是保持价格可见。

    实现功能一:图片与文字中间对齐

    看到设计图就想到使用TextView.drawableLeft属性,加上Html,发现图片居中于全部文字,而不是居中与第一行文字。后面采用Html.img,代码如下:

            String text = String.format(Locale.CHINA, getResources().getString(R.string.qa_channel_ques_str), imageHtml, this.quesStr, price);
    
            setText(Html.fromHtml(text, getQuestionImageGetter(), null));
        private Html.ImageGetter getQuestionImageGetter(){
            final int textSize = (int) getTextSize();
            return new Html.ImageGetter() {
                public Drawable getDrawable(String source) {
                    InsetDrawable insetDrawable = new InsetDrawable(mIconDrawable, 0, 0, (int) dipRight, (int) dipBottom);
                    insetDrawable.setBounds(0, 0, textSize, textSize);
                    return insetDrawable;
                }
            };
        }
    <string name="qa_channel_ques_str"><![CDATA[<src src="%1$s">&nbsp;%2$s<font color="#999999">(¥%3$s)</font>]]></string>

    如果不设置android:lineSpacingExtra属性时,能很好的显示,但是如果设置了该属性后,图片会下移,占用行间距:如图

    这一点很烦人,没办法只好先究其原因。发现,Html.fromHtml会一步步解析给定的在String里面包含的标签,如标签会最终生成一个ImageSpan,传递一个TextView,最红会调用ImageSpandraw()方法,这个方法在DynamicDrawableSpan实现

    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x, 
                     int top, int y, int bottom, Paint paint) {
        Drawable b = getCachedDrawable();
        canvas.save();
        //计算画笔移动距离
        int transY = bottom - b.getBounds().bottom;
        if (mVerticalAlignment == ALIGN_BASELINE) {
            transY -= paint.getFontMetricsInt().descent;
        }
        //移动画笔
        canvas.translate(x, transY);
        b.draw(canvas);
        canvas.restore();
    }

    可以看到就是应为移动了画笔,所以图片才会不与上面的文字对齐,想办法自己重新一个就可以了。但是如果使用Html.fromHtml这个ImageSpan是在`Html自己生成的,如法传入自定义的ImageSpan,但是发现方法public static Spanned fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler)可以传入自定义的TagHandler

        private class ImageHandler implements Html.TagHandler {
    
            private boolean isFirst = false;
            private int textSize;
    
            ImageHandler(float textSize) {
                this.textSize = (int) textSize;
            }
    
            @Override
            public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
    
                if (!"drawable".equalsIgnoreCase(tag) || tag == null || isFirst) {
                    return;
                }
                InsetDrawable insetDrawable = new InsetDrawable(mIconDrawable, 0, 0, (int) dipRight, (int) dipBottom);
                insetDrawable.setBounds(0, 0, textSize, textSize);
    
                isFirst = true;
                int len = output.length();
                output.append("\uFFFC");
                //设置自定义ImageSpan
                output.setSpan(new MyImageSpan(insetDrawable), len, output.length(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    
    }

    MyImageSpan这个直接拷贝ImageSpan代码,主要修改器父类DynamicDrawableSpandraw

    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x,
                     int top, int y, int bottom, Paint paint) {
        Drawable b = getCachedDrawable();
        canvas.save();
        //与descent线对齐
        canvas.translate(x, paint.getFontMetricsInt().descent);
        b.draw(canvas);
        canvas.restore();
    }

    最终调用

    public void setTextStr(String quesStr, String price) {
        if (quesStr == null || price == null) {
            return;
        }
        priceWordCount = price.length() + PRICE_EXTRA_WORD_COUNT;
        this.quesStr = quesStr;
        this.quesPriceStr = price;
    
        String text = String.format(Locale.CHINA, getResources()
                .getString(R.string.qa_channel_ques_str), "", this.quesStr, price);
    
        setText(Html.fromHtml(text, null, new ImageHandler(getTextSize())));
    }

    效果如下:

    实现功能二:文字不能超过三行,多余使用…,但是保持价格可见

    上图可以看到超过三行之后,在问题的后面是显示了...,但是价格依然在那里。这又是如何做到的的呢?

    基本思路是:先让TextView自己测量,在绘制之前,判断是否超过三行,如果超过则获取三行最后一个字符的位置,然后减去价格字符窜的字数,然后重新调用setText()方法。

    @Override
    protected void onDraw(Canvas canvas) {
        if (getLineCount() > MAX_LINE) {
            //获取指定行数的最后一个字的位置
            int endLineNum = getLayout().getLineEnd(MAX_LINE - 1) - priceWordCount;
            if (endLineNum > 0) {
                this.quesStr = this.quesStr.substring(0, endLineNum) + "...";
                setTextStr(quesStr, quesPriceStr);
            }
            //下次如果还是超过指定行数,增加价格字数,知道不超过三行
            PRICE_EXTRA_WORD_COUNT++;
            return;
        }
        super.onDraw(canvas);
    }

    完整TextView:代码:

    public class QAQuestionView extends AppCompatTextView {
        protected final int MAX_LINE = 3;
        protected  int PRICE_EXTRA_WORD_COUNT = 3;
        private int priceWordCount = 0;
        private String quesStr;
        private String quesPriceStr;
    
        private Drawable mIconDrawable;
    
        public QAQuestionView(Context context) {
            this(context, null);
        }
    
        public QAQuestionView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public QAQuestionView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mIconDrawable = getResources().getDrawable(R.drawable.icon_ask_blue);
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (getLineCount() > MAX_LINE) {
                //获取指定行数的最后一个字的位置
                int endLineNum = getLayout().getLineEnd(MAX_LINE - 1) - priceWordCount;
                if (endLineNum > 0) {
                    this.quesStr = this.quesStr.substring(0, endLineNum) + "...";
                    setTextStr(quesStr, quesPriceStr);
                }
                //下次如果还是超过指定行数,增加价格字数,知道不超过三行
                PRICE_EXTRA_WORD_COUNT++;
                return;
            }
            super.onDraw(canvas);
        }
    
    
        public void setTextStr(String quesStr, String price) {
            if (quesStr == null || price == null) {
                return;
            }
            priceWordCount = price.length() + PRICE_EXTRA_WORD_COUNT;
            this.quesStr = quesStr;
            this.quesPriceStr = price;
    
            String text = String.format(Locale.CHINA, getResources()
                    .getString(R.string.qa_channel_ques_str), "", this.quesStr, price);
    
            setText(Html.fromHtml(text, null, new ImageHandler(getTextSize())));
        }
    
        private class ImageHandler implements Html.TagHandler {
    
            private boolean isFirst = false;
            private int textSize;
    
            ImageHandler(float textSize) {
                this.textSize = (int) textSize;
            }
    
            @Override
            public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
    
                if (!"drawable".equalsIgnoreCase(tag) || tag == null || isFirst) {
                    return;
                }
                InsetDrawable insetDrawable = new InsetDrawable(mIconDrawable, 0, 0, 0, 0);
                insetDrawable.setBounds(0, 0, textSize, textSize);
    
                isFirst = true;
                int len = output.length();
                output.append("\uFFFC");
                //设置自定义ImageSpan
                output.setSpan(new MyImageSpan(insetDrawable), len, output.length(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    
    }
    展开全文
  • Qt实现服务器与客户端传输文字和图片(Qt②)

    万次阅读 多人点赞 2017-07-12 15:59:53
    qt 写的socket服务器和客户端实现简单的连接 并接受和发送字符串和图片

    初学者记录学习内容,如有错误请各位前辈指点。
    此次工程完成过程借鉴了下面得两个帖子,附上链接,并致以感谢:
    qt 写的tcp客户端程序实现简单的连接接受和发送消息
    qt写的一个简单的tcp服务器程序,可以接受消息发送数据
    好了闲话少说进入正题。
    了解C语言的盆友们应该知道实现Socket程序传递消息需要以下几点:
    在服务器server端:①创建套接字SOCKET;②bind()函数绑定套接字(和IP,端口Port绑定);③Listen()进入监听状态;④accept()进入接收客户端请求;⑤send()向客户端发送数据;⑥close()关闭套接字。
    在客户端Client端:①创建套接字SOCKET;②connect()向服务器发起请求;③recv()接收服务器传回的数据;④printf()打印传回的数据;⑤close()关闭套接字。
    而在Qt实现Socket的过程中,也与此过程有很多相似之处。

    传输文字的服务器server实现

    在QtDesigner中绘制界面:
    服务器端server界面
    QDialog中两个的PushButton分别命名为pbtnSend和stopButton,以便后面加入槽函数。
    注意进行socket连接之前要在.pro中加入network

    QT       += core gui network

    贴入代码如下:
    sever.h

    #ifndef SERVER_H
    #define SERVER_H
    
    #include <QDialog>
    #include <QTcpSocket>
    #include <QTcpServer>
    #include <QMessageBox>
    #include <QDebug>
    
    namespace Ui {
    class Server;
    }
    
    class Server : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Server(QWidget *parent = 0);
        ~Server();
    
    private slots:
        void on_stopButton_clicked();
        void acceptConnection();
        void sendMessage();
        void displayError(QAbstractSocket::SocketError);
    private:
        Ui::Server *ui;
        QTcpServer *tcpServer;
        QTcpSocket *tcpSocketConnection;
    };
    
    #endif // SERVER_H

    server.cpp

    #include "server.h"
    #include "ui_server.h"
    
    Server::Server(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Server)
    {
        ui->setupUi(this);
        tcpServer=new QTcpServer(this);
        if (!tcpServer->listen(QHostAddress::Any, 7777)) {
                qDebug() << tcpServer->errorString();
                close();
            }
        tcpSocketConnection = NULL;
        connect(tcpServer,SIGNAL(newConnection()),
        this,SLOT(acceptConnection()));
        connect(ui->pbtnSend,SIGNAL(clicked(bool)),
        this,SLOT(sendMessage()));
    }
    
    Server::~Server()
    {
        delete ui;
    }
    
    void Server::acceptConnection()
    {
        tcpSocketConnection = tcpServer->nextPendingConnection();
        connect(tcpSocketConnection,SIGNAL(disconnected()),this,SLOT(deleteLater()));
        connect(tcpSocketConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
    }
    
    void Server::on_stopButton_clicked()
    {
        tcpSocketConnection->abort();
        QMessageBox::about(NULL,"Connection","Connection stoped");
    }
    
    void Server::sendMessage()
    {
        if(tcpSocketConnection==NULL)
            return;
        QByteArray block;
        QDataStream out(&block,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_5_8);
        out<<(quint16)0;
        out<<"Hello TCP!@_@!";
        out.device()->seek(0);
        out << (quint16)(block.size() - sizeof(quint16));
        tcpSocketConnection->write(block);
    }
    
    void Server::displayError(QAbstractSocket::SocketError)
    {
         qDebug() << tcpSocketConnection->errorString();
    }

    现在对server.cpp进行解释:
    引用查到的一段对QTcpServer和QTcpSocket基本操作的描述,如下涉及到的几个函数都是特别重要的。

    QTcpServer的基本操作:
    1、调用listen监听端口。
    2、连接信号newConnection,在槽函数里调用nextPendingConnection获取连接进来的socket。
    QTcpSocket的基本能操作:
    1、调用connectToHost连接服务器。
    2、调用waitForConnected判断是否连接成功。
    3、连接信号readyRead槽函数,异步读取数据。
    4、调用waitForReadyRead,阻塞读取数据。

    在调用这几个函数之前先在.h文件中做声明指针变量:

    private:
        QTcpServer *tcpServer;
        QTcpSocket *tcpSocketConnection;

    在.cpp文件中

    tcpServer=new QTcpServer(this);
    tcpSocketConnection = NULL;

    注意之后要在tcpSocketConnection的基础上操作数据,所以初始化要保证当前无连接,即赋值为NULL。
    然后在构造函数中设置IP地址和端口号:

    if (!tcpServer->listen(QHostAddress::Any, 7777)) {
                qDebug() << tcpServer->errorString();
                close();
            }

    QTcpServer调用Listen()监听,使用了IPv4的本地主机地址,等价于QHostAddress(“127.0.0.1”),端口号设为”7777”。listen()函数返回的值是bool型,所以如果监听失败时,会把错误原因打印到控制台,并关闭连接。

    用QT实现并不需要像C语言那么麻烦,当我们设置好IP和端口进行监听时,用我的理解就是服务器进入了循环,会不断监听检查发来的连接,当有同样的IP和端口的连接申请发来的时候,QTcpSocket会发射newConnection()信号,在代码的槽函数中会触发acceptConnection()函数。

    tcpSocketConnection = tcpServer->nextPendingConnection();

    当信号发来的时候,通过调用QTcpServer的nextPendingConnection()函数得到的socket连接句柄tcpSocketConnection ,注意之后对于信号和数据的操作都是在这个句柄基础上进行的。
    注意到此函数中仅有对tcpSocketConnection进行操作,但是没有在开头new一块内存去保存tcpSocketConnection,这是因为通过nextPendingConnection()得到句柄的过程就会被分配一块内存去保存,所以不用忘记了在之后释放内存空间,即之后的deleteLater()函数。
    之后的两个connect语句,断开后删除连接,运行出错将错误信息打印到控制台。

    最后来看服务器端最重要的一个槽函数sendMessage()。
    当触发pbtnSend按钮的clicked()信号,将固定消息“Hello TCP!@_@!”发送。首先连接句柄tcpSocketConnection是否为空。
    然后用到了QByteArray,这在Qt传输数据时非常重要,它可以存储raw bytes即原始字节,将文字或者图片转化为raw bytes发送,在接收端进行解析。
    QDataStream则提供了一个二进制的数据流。看代码:

        QByteArray block;
        QDataStream out(&block,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_5_8);
        out<<(quint16)0;
        out<<"Hello TCP!@_@!";
        out.device()->seek(0);
        out << (quint16)(block.size() - sizeof(quint16));
        tcpSocketConnection->write(block);

    将仅可写入WriteOnly的数据流out与block进行绑定。
    设置数据流out的版本,注意客户端和服务器端使用的版本要相同,这里我们使用的是Qt5.8。然后通过C++的重载操作符<<实现对流的操作。
    这里着重说一点,使用<<的时候并不关心输入的类型,换句话说无论是什么类型写入数据流,在读出的时候都会以写入的顺序和类型读出,而不用考虑占几个字节,需要一个一个字节取出来,高位低位组合起来等等情况。
    比如此程序中,先以quint16类型(2个字节)的输入”0”占位,然后写入字符串”Hello TCP!@_@!”。seek(0)将指针移动到0所在的那一位处,block.size()得出block的长度15,sizeof(quint16)得出一个quint16类型的长度为2,相减得13覆盖保存到刚才用0占位的保存quint16类型的内存中,这就是传输的数据的长度,与数据一起传给服务器用于比对数据是否传输完整。
    注意quint16是QT软件下的一种自定义类型,代表16位的无符号整型,可以存储2^16个数字,就是0-65535,以此储存发送的文字的长度足以。但是如果需要传输图片的大小就需要使用quint32类型来储存,在后面中我们会用到。
    最后是QTcpSocket的write函数,将QByteArray类型的block写入Socket缓存中,之后就是客户端的工作了。

    传输文字的客户端Client实现

    在QtDesigner中绘制界面:
    客户端Client界面
    QDialog下两个QLineEdit用于填入端口号和IP地址,PushButton命名为sendButton用于触发向服务器的连接申请。QTextEdit命名为messageShow用于显示从服务器传来的字符串。
    贴入代码如下:

    client.h

    #ifndef CLIENT_H
    #define CLIENT_H
    
    #include <QDialog>
    #include <QTcpSocket>
    #include <QObject>
    #include <QMessageBox>
    #include <QDebug>
    #include <QDateTime>
    
    
    namespace Ui {
    class Client;
    }
    
    class Client : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Client(QWidget *parent = 0);
        ~Client();
    
    private slots:
        void on_sendButton_clicked();
        void showMessage();
        void displayError(QAbstractSocket::SocketError);
    
    private:
        Ui::Client *ui;
        QTcpSocket *tcpSocket;
        quint16 blockSize;
    };
    
    #endif // CLIENT_H
    

    client.cpp

    #include "client.h"
    #include "ui_client.h"
    
    Client::Client(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Client)
    {
        ui->setupUi(this);
        tcpSocket = new QTcpSocket(this);
        connect(ui->sendButton,SIGNAL(clicked()),this,SLOT(on_sendButton_clicked()));
        connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(showMessage()));
        connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                            this, SLOT(displayError(QAbstractSocket::SocketError)));
        blockSize = 0;
    }
    
    Client::~Client()
    {
        delete ui;
    }
    
    void Client::on_sendButton_clicked()
    {
        if(tcpSocket->state()!=QAbstractSocket::ConnectedState)
        {
            tcpSocket->connectToHost(ui->ipLineEdit->text(),ui->portLineEdit->text().toInt());
    
            if(tcpSocket->waitForConnected(10000))
            {
                QMessageBox::about(NULL, "Connection", "Connection success");
            }
            else
            {
                QMessageBox::about(NULL,"Connection","Connection timed out");
            }
        }
        else
            QMessageBox::information(NULL,"","Connected!");
    }
    
    void Client::showMessage()
    {
        QDataStream in(tcpSocket);
        in.setVersion(QDataStream::Qt_5_8);
        if(blockSize==0)
        {
            if(tcpSocket->bytesAvailable()<(int)sizeof(quint16))
                return;
            in >> blockSize;
        }
       if(tcpSocket->bytesAvailable()<blockSize)
            return;
        char* buf=new char[512];
        in >> buf;
        QDateTime time = QDateTime::currentDateTime();
        QString str = time.toString("yyyy-MM-dd hh:mm:ss");
        ui->messageShow->setText(buf+str);
        if(buf)
            delete buf;
    }
    
    
    void Client::displayError(QAbstractSocket::SocketError)
    {
        qDebug() << tcpSocket->errorString();
    }
    

    现在对client.cpp进行解释。
    多余的东西不再赘述,点击sendButton运行槽函数on_sendButton_clicked()。这里引用一段对QAbstractSocket的描述:

    QAbstractSocket都有一个状态,而我们可以通过调用成员函数state返回这个状态,才开始的状态是UnconnectedState,
    当程序调用了connectToHost之后,QAbstractSocket的状态会变成HostLookupState,,
    如果主机被找到,QAbstaractSocket进入connectingState状态并且发射HostFound()信号,当连接被建立的时候QAbstractSocket 进入了connectedState状态 并且发射connected()信号,如果再这些阶段出现了错误,QAbstractSocket将会发射error()信号,无论在什么时候,如果状态改变了,都会发射stateChanged(),如果套接字准备好了读写数据,isValid()将会返回true。

    如上所述调用state()判断QAbstractSocket是否是connectedState,即已经连接的状态。如果尚未连接继续执行,调用随后调用QTcpSocket的connectToHost(从控件中获取的IP和端口号)连接服务器,调用waitForConnected判断是否连接成功,但如果是已经连接成功弹出提示框。
    QMessageBox弹出提示语对话框,常用于帮助你判断socket是否连接成功。
    在服务器中通过write()将数据写入socket缓冲区,在已经连接成功的情况下客户端当有数据要读的时候,会触发readyRead()信号,随后执行showMessage()槽函数,showMessage()函数是将传过来的数据类型转化后输出。声明数据流in接收数据,设置QT版本。
    注意在.h中定义:

    private:
     quint16 blockSize;

    quint16 类型的blockSize用于从数据流中接收之前保存为quint16 的字符串的大小,用来进行数据是否传输完整的比对,并在.cpp中赋值为blockSize = 0。

    tcpSocket->bytesAvailable()返回已经接收到的可以被读出的字节数,(int)sizeof(quint16)返回一个quint16类型变量的大小,只有当前者大于后者说明数据的长度已经传输完整,则保存到blockSize变量中,否则直接返回,继续接收数据。
    随后用blockSize值进行比对,只有当接收到的字节数大于blockSize的值才说明数据全部传输成功,否则返回继续接收数据。

    传输数据的大小和比对,这两步是基本步骤,必不可少
    定义一个暂时保存数据的char型数组的指针,new一段大小为512的内存,将接下来的char型的字符串输入其中。一定记得在最后删除指针。
    关于删除指针着重说一点——

    关于C++中的析构函数,分配到栈(局部内存管理)的不需要释放,分配到堆(全局内存管理)需要释放。一般局部对象在局部函数结束的时候会自动释放。
    New一个内存空间或者malloc()动态分配内存空间一般都需要自己在析构函数中释放。比如在此程序中,函数运行结束之后指向内存空间的指针buf最后会被自动删除,而这一块储存空间并不会被释放,而且也将再无法对其进行操作,长此以往内存会愈来愈小。因此有两条路可选,一是对该指针进行保存以便以后对其指向的内存空间进行管理。二是在函数结束之前释放内存空间。

    最后获取当前的时间和日期显示到textEdit中。结束。

    传输图片的server和client实现

    关于socket的连接,这里将不再累述,只对发送和显示图片的过程进行简单地讲解。
    同上,先再QTdesigner中绘制客户端和服务器的界面,同传输文字大致相同,只需将客户端界面中的textEdit换成QLabel用于显示图片。
    服务器中发送图片和客户端中接收图片的槽函数如下:

    void pictureSever::on_sendPictureButton_clicked()
    {
        if(tcpSocket==NULL)
            return;
        QByteArray block;
        QDataStream out(&block,QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_5_8);
        out<<(quint32)buffer.data().size();
        block.append(buffer.data());
        tcpSocket->write(block);
    }

    在.h中声明

    private:
    QBuffer buffer;

    在.cpp的构造函数中,将图片保存在buffer中:

    QPixmap(":/new/prefix1/sendPicture/007.bmp").save(&buffer,"BMP");

    图片在项目的资源文件中。

    此处将字符串读入socket中的方法与上例中的方法大致相同,先读入数据的大小,后读入数据。但过程不同,两个过程并无太大区别,可自行选择。
    不过要注意的就是上面已经谈过的,这里使用quint32而不是quint16来存储图片的大小。

    void pictureClient::showPicture()
    {
        while(tcpSocketConnection->bytesAvailable()>0)
        {
            if(blockSize==0)
            {
                QDataStream in(tcpSocketConnection);
                in.setVersion(QDataStream::Qt_5_8);
                if(tcpSocketConnection->bytesAvailable()<sizeof(quint32))
                    return;
                in>>blockSize;
            }
    
            if(tcpSocketConnection->bytesAvailable()<blockSize)
                return;
    
            QByteArray array = tcpSocketConnection->read(blockSize);//blockSize作read()的参数。
            QBuffer buffer(&array);
            buffer.open(QIODevice::ReadOnly);
    
            QImageReader reader(&buffer,"BMP");
            QImage image = reader.read();
            blockSize=0;//①
    
            if(!image.isNull())
           {
                image=image.scaled(ui->showPicturelabel->size());
                ui->showPicturelabel->setPixmap(QPixmap::fromImage(image));
                blockSize=0;//②
           }
        }
    }

    同样的方式,先确定用quint32变量保存的图片大小的的值已经传入,然后比对确定图片完全传入。
    注意这里要使用QImageReader将图片的数据流转化回BMP格式,必须使用QBuffer,将数据装入QBuffer类型的变量中进行转化。
    QImageReader的帮助文档
    QBuffer的帮助文档
    有概念性的疑问一定去找Qt帮助文档,这才是权威。
    最后说一点:blockSize的问题,在传输字符串时,由于我们要传输的数据比较短,我们就当作记录字符串长度的变量一次性传入成功,其实这是存在问题的。数据较多时,并不一定能一次成功的,应该使用传输图片时使用的while循环比对判断。因为要使用blockSize==0作为判断条件,在循环体的结尾处要将blockSize再置为0,①处是传输异常情况下走不到下面的if结构中时的情况,②处是传输正常情况下的置0。
    最后将图片读入到image,自适应Label的大小并显示。

    有点啰嗦,如有错误还望指正,谢谢。

    展开全文
  • 在项目中我们经常遇到需要显示圆形头像的需求,一般我们都使用hdodenhof/CircleImageView的这个开源控件实现(简洁,没多余的东西)。  而在的项目中我经常遇到这样的一个需求:如果用户上传了头像就显示圆形头像,...
  • 去除.gif图片中的文字

    千次阅读 2011-02-26 00:04:00
    教你去除.gif图片中的文字 朋友们,大家有没有遇到过这种情况,当我们找到一张很喜欢的.gif图片,可是图片上却有一些多余的文字,我们很想把它去掉,换成自己喜欢的文字,可是却没办法?现在教大家一种...
  • 自定义View常用例子(点击展开隐藏控件,九宫格图片控件) 今天博客的主要内容是两个常见的自定义控件,第一个是我们经常看到的点击隐藏点击查看控件,第个控件是仿微信朋友圈的九宫格图片控件,相对上一篇的...
  • POI在指定位置插入文字表格图片

    千次阅读 2018-01-15 10:39:43
    "第行第列" ) ; // tableOneRowTwo .getCell ( 2 ) .setText ( "第2行第3列" ) ; XWPFTableRow tableOneRow3 = tableOne .createRow () ; // ---顺序增加行后,忽略第 1 、 2 单元格,直接插入 3 、 4 ...
  • 图片、多行文字的水平垂直居中

    千次阅读 2014-03-04 15:34:53
    关于图片垂直居中显示,想必很多写css的人都研究过,或者说是搜寻过方法。淘宝团队似乎提供了一种不错的方法,用font-size解决IE下垂直居中的问题,是个好方法吗?是的,方法是不错,可是问题也很多:不支持im
  • **C#将用多个空格分开字符的输入字符串前的空格去掉且将每个字符之间的多余空格去掉只留下一个空格分隔字符**欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接...
  • 自绘图元放到左边和上边之外,部分在内进行拉伸后,拉伸多余的区域无法碰撞 示意图 解决后的目标效果 解决方法 变换之前或之后一定要调用一次prepareGeometryChange(); void RectItemBase::...
  • 1、在css中给div添加上“vertical-align:middle”属性        找回密码    css代码:  复制代码 代码如下: #denglu *{  vertical-align:middle;...2、把图片设置为背景图片 如果我们的图片
  • 现在搜集图片资料的时候,无论是在网上直接查找还是在视频上拷屏时都会遇到一个问题,便是上面的广告,有些是个人,有些是某个组织,还有些是企业,为了提高一下知名度而为。还有其他一些原因,图片中含有自己不...
  • 本文综述 想必写css的都知道如何让单行文字在高度固定的容器内垂直居中,但是您知道或者想过让...关于图片垂直居中显示,想必很多写css的人都研究过,或者说是搜寻过方法。淘宝团队似乎提供了一种不错的方法,用fon
  • 该文章主要是通过C#网络编程的webBrowser获取网页中的url并简单的尝试下载网页中的图片,主要是为以后网络开发的基础学习.其中主要的通过应用程序结合网页知识、正则表达式实现浏览、获取url、下载图片三个功能.而且...
  • 个难以克服的困难就是数据量,要想得到足够精确的结果,必须依赖于足够量的数据来训练网络模型。本节我们先看看第个问题如何解决。 我们将开放一个神经网络,用于识别猫狗照片,用于训练模型的照片数量不多,...
  • 前端性能优化之优化图片

    千次阅读 2017-08-21 15:52:56
    前端图片优化一直以来都是热门话题,从需求上来看,很多站点往往是图片体积大于代码体积, 图片请求多余代码文件请求, 给前端的性能带来了很大的困扰,那么应该如何解决呢?    零、 认识图片  我们...
  • 开始打算试试用python将大量的图片拼接成心形的功能,但是没接触过python用于处理图片的内容,因此在这里先做一个简单的入门。 这一篇博客写的是将大量图片拼接成正方形的合成图片,如果想改变策略,可根据自己的...
  • 而且不具有通用型,换一幅图片参数就得重新调整。这种方式效率比较低,但是以我目前的水平来说暂时没有好的代替方案,只能先用这种方式。我现在就想先把完整的功能实现了之后再想着去优化。希望以后能研究出一种...
  • 修改日志 2016.05.12 之前的程序存在两个问题: 1)从相册选择的图片如果比较大,会失败;... 功能实现 1 获得图片 2上传到服务器并保存 3从服务器中获得图片并显示 4辅助工具 一. 整体功能描述整理了一下主要
  • 为DNN开发变换图片模块的总结

    千次阅读 2008-04-24 13:10:00
    DNN 的变换图片模块开发靠一段落,在此总结...用vs2005的My templates中的DotNetNuke dynamic module新建一模块,将多余的东东剔除。得以一个干净的module.于是乎,现在的工作重点就是考虑如何实现变换图片了。直接
  • 最近项目中需要处理与图片相关的布局,不得不说图片这玩意真想要得到完美的展示效果还真是要费些力气。因为图片的尺寸或者比例各不相同。所以想要不同尺寸的图片有好的显示效果,你就...
  • JPG、PNG和GIF图片的基本原理及优化方法 一提到图片,我们就不得不从位图开始说起,位图图像(bitmap),也称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的...
  • 微信小程序居中、居右、横纵布局 1、相对... 居底的还可以看看另一篇文章:底部购物车 4、文字在图片中间 效果图: 瘦身燃脂 这四个就是在图片的正中间 代码 wxml <view class='container'> <view class="view_1"> ...
  • .card_s{ clear:both; float:left;}.row{ width:100%; clear:both; margin-right:auto; margin-left:auto;} .p_show { display:inline; margin-right:1px; float:left;}.a_text{ width:70px;...
  • (3)推荐使用第种方法,因为它在创建UITabBarItem时可以一次性的把文字、选中图片、未选中图片等不同状态都定义出来。 四、关于tabbar上得More (1)当标签多余5个时,标签控制器会自动创建一...
  • python 图片中的表格识别

    万次阅读 多人点赞 2018-07-09 14:15:35
    表格图片的内容识别 接到个任务需要将几万张带表格的图片转换成结构化数据。 ...最终算是完成任务,但是识别...其实就是将单元格中的文本区域裁剪出来,将多余的空白去掉; 3. 大图片的识别。对于大图片用图像...
  • 图片隐藏数据的技术

    千次阅读 2017-06-14 22:07:07
    图片中隐藏数据是一件可繁可简的事情。 ★尾部追加法  先介绍最简单的一种方法。 ◇技术原理  顾名思义,"尾部追加法"就是把要隐藏的文件追加到图片尾部。这种方法不会破坏图片原有的任何数据,因此...
  • 对于Excel中的很多对象,比如单元格(Cell),图形(shape),图表(chart)等等,有时需要将它们保存成一张图片。就像截图一样。 最近做一个Excel相关的项目,项目中遇到一个很变态的需求, 需要对Excel中的一些...
  • 制作图片经常能用到PS,PS功能很多,但没有详细的指南,操作起来就无从下手,例如我们需要把图片多余的文字去除,相信有很多小伙伴是不知道怎样操作的,下面小编就给大家讲讲,一起来看看吧! 方法一: 具体操作...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,505
精华内容 10,202
关键字:

多余二字图片